Comments (43)
@jeremiahjstacey - Thanks for the suggestion. On one hand it may make the code cleaner (@davewichers you relocated logging statements, don't you? This looks fine to you?). On the other hand, re running the validation changing the boolean setting still needs to reset the stream anyway to accomplish that goal. I really could not find a way yet to do it with the specific InputStream used in the test cases, I need to make the stream rewindable somehow (cloning was not an option in the past).
Sadly I can’t keep looking at this today but I'll see what I can do tomorrow.
from antisamy.
@jeremiahjstacey @gerardocanedo - Standby. I found the problem. I just have to figure out how to fix it. Hopefully won't take too long. This looks fishy: "Setting AntiSamy policy schema validation to 'false' because 'owasp.validator.validateschema' system property set to: 'true'." :-)
Apparently Boolean.parseBoolean() and Boolean.getBoolean() do different things ... :-). Fixed now, just cleaning up.
from antisamy.
Fixed in v1.6.2 that was just released.
from antisamy.
@spassarop - Hey Sebastian - can you write a test case to verify this, and then fix it, if verified?
from antisamy.
from antisamy.
@davewichers - BTW, this is a showstopper for the planned 2.2.3.0 ESAPI release. These tests still fail with the same "Stream closed" IOException
as their root cause even if this test is run as:
mvn -Dowasp.validator.validateschema=false test
so I am not confident that this leaves any workaround except for correcting the application's AntiSamy policy file that otherwise doesn't pass schema validation. And since it the invalid '<html-entities>
' node was in every single release of ESAPI's antisamy-esapi.xml file dating back to as far as 10 years or so, I think this will affect a lot of ESAPI users even though our new release will be removing that unused, invalid node. And yes, I will surely draw attention to this in our accompanying release notes, but there is significant evidence that people don't pay much attention to them even after they encounter problems. (They just figure it is easier to create a GitHub issue or to privately email us instead.)
As @jeremiahjstacey pointed out, I think the fix is just to drop in a call to InputStream.reset()
before the second call to getDocumentElementFromSource()
to reset the input stream. (That ought to work in most cases unless the input stream is associated with something like a pipe or stdin.) Maybe that is what the call
source = getResetSource.call();
is intended to do, I don't know. I do know that @jeremiahjstacey spent a long time in looking at this and I do totally trust his judgement though.
from antisamy.
@kwwall - I figured as much. Hopefully @spassarop can get to this quickly as he implemented the enable/disable feature, but apparently missed this specific use case. I'd expect this would be an easy fix that we can get done in the next couple of days.
from antisamy.
Well that's a deep analysis indeed. To give some context:
This was potential issue since the implementation of validation warnings and retrying validation. The latter is the conflictive one because when it comes to stream reading, that gave me a heachache.
My solution to re read a stream is the one you wrote, resetting it:
private static Element getTopLevelElement(InputStream is) throws PolicyException {
final InputSource source = new InputSource(is);
source.getByteStream().mark(0);
return getTopLevelElement(source, new Callable<InputSource>() {
@Override
public InputSource call() throws IOException {
source.getByteStream().reset();
return source;
}
});
}
As there are two main ways of creating a policy (InputStream
or URL) to avoid repeating LOTS of code I just encapsulated the reset behavior in a callable which is the getResetSource
argument. In the case of InputStream
, reset failed if I didn't use .mark(0)
before.
Maybe the big problem here is that the InputStream
is wrapped in an InputSource
object, which I sadly could not avoid when implementing this. Avoiding re validation is an absolute solution but it wouldn't be so friendly for users I guess. However, I'm telling you all this without having executed the tests yet. I'll tell you what I get from all this but I wanted to show you the whole picture before.
from antisamy.
@spassarop, I was looking at it and I wonder if the logging can be pushed down another level? I'm not overly familiar with the API, but I think this might work:
protected static Element getTopLevelElement(InputSource source, Callable<InputSource> getResetSource) throws PolicyException {
try {
return getDocumentElementFromSource(source, validateSchema);
} catch (SAXException | ParserConfigurationException | IOException e) {
throw new PolicyException(e);
}
}
private static Element getDocumentElementFromSource(InputSource source, boolean schemaValidationEnabled)
throws ParserConfigurationException, SAXException, IOException {
Element returnElement;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
/**
* Disable external entities, etc.
*/
dbf.setFeature(EXTERNAL_GENERAL_ENTITIES, false);
dbf.setFeature(EXTERNAL_PARAM_ENTITIES, false);
dbf.setFeature(DISALLOW_DOCTYPE_DECL, true);
dbf.setFeature(LOAD_EXTERNAL_DTD, false);
// Build the non-validaiton implementation before assigning the schema.
DocumentBuilder nonValidatingBuilder = dbf.newDocumentBuilder();
nonValidatingBuilder.setErrorHandler(new SAXErrorHandler());
getPolicySchema();
dbf.setNamespaceAware(true);
dbf.setSchema(schema);
DocumentBuilder validatingBuilder = dbf.newDocumentBuilder();
validatingBuilder.setErrorHandler(new SAXErrorHandler());
try {
Document validDoc = validatingBuilder.parse(source);
returnElement = validDoc.getDocumentElement();
if (!validateSchema) {
// We warn when the policy has a valid schema, but schema validation is disabled.
logger.warn("XML schema validation is disabled for a valid policy. Please reenable policy validation.");
}
} catch (SAXParseException spe) {
if (schemaValidationEnabled) {
throw spe;
}
}
//Only reaches here if the schema is valid or we have schemaValidationEnabled set to false
if (!schemaValidationEnabled && returnElement == null) {
Document nonvalidDoc = nonValidatingBuilder.parse(source);
returnElement = nonvalidDoc.getDocumentElement();
// We warn when the policy has an invalid schema, but schema validation is disabled.
logger.warn("Invalid policy file: " + e.getMessage());
}
return returnElement;
}
The stream may still need to be reset on some scale, I'm honestly not certain on that. It does reduce the nesting calls in the exception blocks, so I figured I'd throw it out in case the idea would be useful to you.
from antisamy.
@spassarop - Lets focus on getting this scenario to functionally work, and not break any of the other scenarios that currently work. And then we can figure out the best way to handle logging for all scenarios, with this one additional new one now working.
from antisamy.
@spassarop, it may be a little cheaty -- ByteArrayInputStream does not implement close. If we read the original inputStream into a byte[], then build a ByteArrayInputStream to feed to the InputSource then the close behavior may not actually matter.
I have not tested this. In theory, it might work.
private static Element getTopLevelElement(InputStream is) throws PolicyException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
int nRead;
byte[] data = new byte[1024];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
} catch (IOException e) {
logger.warn("Unable to read contents from stream");
throw new PolicyException( e);
}
byte[] byteArray = buffer.toByteArray();
final InputSource source = new InputSource(new ByteArrayInputStream(byteArray));
source.getByteStream().mark(0);
return getTopLevelElement(source, new Callable<InputSource>() {
@Override
public InputSource call() throws IOException {
source.getByteStream().reset();
return source;
}
});
}
References:
https://www.baeldung.com/convert-input-stream-to-array-of-bytes
https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#close()
from antisamy.
Something straight forward but it may be the solution
Instead of setting always true to validate schema, I'm setting the validateSchema variable.
It works for the direct config.. There may be something else with the system property.
I'm working on it
protected static Element getTopLevelElement(InputSource source, Callable getResetSource) throws PolicyException {
// Track whether an exception was ever thrown while processing policy file
Exception thrownException = null;
try {
return getDocumentElementFromSource(source, true);
...
}
protected static Element getTopLevelElement(InputSource source, Callable getResetSource) throws PolicyException {
// Track whether an exception was ever thrown while processing policy file
Exception thrownException = null;
try {
return getDocumentElementFromSource(source, validateSchema);
...
}
from antisamy.
@gerardocanedo, I thought about that too. The cost there is that you'll lose the distinct logging to call out that schema validation is disabled. If not having the logging is an acceptable change, then that does cleanly remove the issues with the InputSource.
from antisamy.
I'd prefer to have the same logging behavior in this scenario as we've implemented for the other ones already. i.e., always warn one way or the other when validation is disabled.
from antisamy.
I'm getting the following output from both test cases:
[main] WARN org.owasp.validator.html.Policy - Attempting to load AntiSamy policy from an input stream.
[main] WARN org.owasp.validator.html.Policy - XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation.
[main] WARN org.owasp.validator.html.Policy - Attempting to load AntiSamy policy from an input stream.
[main] WARN org.owasp.validator.html.Policy - XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation.
I did some changes to the static code using the getter and setter
static {
String validateProperty = System.getProperty(VALIDATIONPROPERTY);
if (validateProperty != null) {
setSchemaValidation( Boolean.getBoolean(validateProperty));
logger.warn("Setting AntiSamy policy schema validation to '" + getSchemaValidation()
+ "' because '" + VALIDATIONPROPERTY + "' system property set to: '" + validateProperty + "'");
}
}
from antisamy.
I had to appease my curiosity on the ByteArrayInputStream, and wanted to share the results. I duplicated my original tests and rebuilt the streams to pass into Policy.instance(InputStream)
. (File Attached below)
Using the ByteArrayInputStream appears to resolve the issue without requiring any other code changes.
Downside is having the file in memory to support the implementation. Significantly large files may have an impact on overall application performance.
(Failed tests are the same ones listed in my original comment)
Tests in error:
testSystemProp(antisamy_tests.InvalidPolicyTest): java.io.IOException: Stream closed
testDirectConfig(antisamy_tests.InvalidPolicyTest): java.io.IOException: Stream closed
Tests run: 4, Failures: 0, Errors: 2, Skipped: 0
from antisamy.
IMHO, changing the true constant to validateSchema does the trick. It does log a warning
[main] WARN org.owasp.validator.html.Policy - XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation.
Also, there's a test case that sets a system property.
System.setProperty(ANTISAMY_PROJECT_PROP_SCHEMA_VALIDATION, "false");
If the Policy class is already loaded, setting the property has no effect.
Is this expected behavior ? I believe so
from antisamy.
@gerardocanedo wrote
If the Policy class is already loaded, setting the property has no effect.
Is this expected behavior ? I believe so
In the AntiSamy world, it might not be the correct behavior because you can an application that is using multiple policy files at once. In the ESAPI world--the way AntiSamy us is currently used there, it should be fine, as you can only use a single AntiSamy policy file that you need to have selected before AntiSamy is loaded.
The real question is: what effect should it have in AntiSamy if one first sets the owasp.validator.validateschema
property to "false" and processes a policy where they want to ignore the schema, and then either clears that property using System.clearProperty()
or instead, subsequently sets that property to "true" and then processes a 2nd policy file? Do you want the use of any subsequent policy files to skip XML schema validation? I don't think so.
Now obviously, if an application wants to use AntiSamy in that manner, it would be better off to use Policy.setSchemaValidation()
, but people don't always do the obvious thing, especially when you give them multiple options to shoot themselves in the foot. Also keep in mind that to some degree we are trying not to break client applications here which is one reason why the System
property approach was proposed, especially for ESAPI clients. (ESAPI had a bogus XML node called <html-entities>
going back 10+ years or so, so @davewichers added it partly for them. If he hadn't, I would have and just would done something similar because I don't want to break production code.) For ESAPI clients though, it isn't a concern (unless they are also using AntiSamy separately) since ESAPI only can currently only ever use a single AntiSamy policy file.
So to get back to answering your question, I'm not sure there is a clear cut answer in all the edge cases here. @davewichers, what do you think? How do you want it to behave in the scenario I've portrayed?
from antisamy.
@kwwall - To me, system properties are once and done. If you change a system property while its already loaded, it won't change the policy in affect. That is what the individual set methods are for, if you want to change validation between one policy and another. If the property is the easiest thing for you, then disable it if you have even 1 non-compliant policy. Once you get all the policies fixed to be valid, then you can reenable it. So - the 'as is' implementation of the system property static initializer is fine with me.
from antisamy.
Ok. I'm working on a test case with it's own classloader to verify the property.
Once it's done, i'll commit the fix
from antisamy.
from antisamy.
@spassarop, it may be a little cheaty -- ByteArrayInputStream does not implement close. If we read the original inputStream into a byte[], then build a ByteArrayInputStream to feed to the InputSource then the close behavior may not actually matter.
Honestly, independently of any logging behavior changes, this may be the best solution regarding re executing the parser. About the files being in memory... I don't know if a policy XML will ever be large enough to provoke a performance issue, but if it does, is only while parsing de Policy which is a really small ammount of time (at least from what I've seen).
Besides, I'm not expert here, but if you reset a stream, doesn't that mean that the stream must be somehow in memory already to return to the 0 index?
from antisamy.
if you reset a stream, doesn't that mean that the stream must be somehow in memory already to return to the 0 index?
That's my understanding. The Stream needs to hold a certain set of bytes in order to read ahead or reset back. I've seen this used for stream processing where you can read a chunk of a file for processing. I think it would work for an entire file too.
You are right. It will need to be entirely in memory either way in this case.
I also think that using the reset behavior requires the stream to be open, so I think the code would have to rebuild the input stream anyway in order to process the file more than once since something is closing the stream in the document generation process.
from antisamy.
Well in that case... if everyone agrees, that stream pre-reading could be impacted on 1.6.2. It should be independent from Gerardo's changes as they do not touch the reset logic itslef.
Off-topic: My fist words remind me of this:
from antisamy.
@spassarop Looked a bit more at the method I provided for the ByteArrayInputStream (above) and determined there is a possible resource leak since the original stream is never closed.
Made some updates to wrap the InputStream in an InputReader, which allows the use of try-with-resources to pull the file into memory and should guarantee the stream is cleaned up after use.
Updated method below, if this is useful to you.
private static InputStream toByteArrayStream(InputStream in) throws IOException {
byte[] byteArray;
try (Reader reader = new InputStreamReader(in)) {
char[] charArray = new char[8 * 1024];
StringBuilder builder = new StringBuilder();
int numCharsRead;
while ((numCharsRead = reader.read(charArray, 0, charArray.length)) != -1) {
builder.append(charArray, 0, numCharsRead);
}
byteArray = builder.toString().getBytes();
}
return new ByteArrayInputStream(byteArray);
}
from antisamy.
@spassarop - After merging I reviewed/tested your changes, and found some problems. I added 4 test cases to the new ESAPI related test cases, 1 or 2 of which fail when using either the old or new version of getTopLevelElement(InputSource source, Callable getResetSource).
If you start reading at: https://github.com/nahsra/antisamy/blob/1.6.2/src/main/java/org/owasp/validator/html/Policy.java#L370 I added comments in the file itself describing the problems I found. I also added back in the old version of this method and made a few improvements/fixes to your new version.
However, both methods still have problems and I'm not sure if the best course of action is to fix the old one, or the new one, which is why they are both in there now. The new version is problematic because the invalid policy error messages don't really explain the real validation problem. As such, I suspect it is better to fix the old method to work properly, pass all the test cases, and not fail when trying to reset different kinds of streams.
Maybe the very helpful @jeremiahjstacey can help us figure out the best approach. Jeremiah - can you review my comments inside the updated Policy file and let us know if you have any brilliant ideas?
from antisamy.
My current thought is that if the original implementation provided a more accurate workflow for the desired logic blocks, then it seems like a shorter path to restore that logic. From conversations in this thread with @spassarop, I believe that we can use the resource-safe ByteArrayInputStream wrapper (defined here) and use that for the stream fed to the InputSource. At that point, the original issue with the closed streams should be resolved, and the original logic flow will be restored.
At that point, the test cases that @gerardocanedo has provided will need to be updated to reflect these expectations. Tests should also be added for the explicit logging expectations of the behavior to capture the requirements in future efforts. (my opinion)
From a recommendation standpoint, I think that makes the most sense to me.
from antisamy.
If we wanted to keep the updates to Policy.java, then pushing the logging down another level may also provide a path to resolution.
We touched on that possible update in this comment
Test updates may still be needed. Tests to assert the logging behavior would still be recommended.
from antisamy.
Regarding the use of ByteArrayInputStream wrapper, I think we'd have to do that inside of the AntiSamy methods as the caller should be blissfully unaware that the stream needs to be resettable. As such, I don't think we should have to change the test cases at all. Is there a way to 'test' whether a given stream is resettable, and if not, wrap it. But if it already is, you avoid double wrapping it for no reason?
I already have test cases that test the logging behavior, but they don't just pass/fail. Rather you have to look at them to make sure they look right. That's how I implemented/tested the logging behavior in the first place and noticed the problem this time. However, if there was a way to grab the 'most recent' log messages and make sure they contain certain strings, we could add pass/fail type test cases so human review wasn't required anymore. However, we can deal with that later. Let's get it working as desired, and then we can see if we can figure out a way to make the desired logging behavior automatically testable.
from antisamy.
from antisamy.
@gerardocanedo - test it yourself. Without reparsing the original stream, the error messages returned are completely different, and not helpful.
from antisamy.
@davewichers, `InputStream.markSupported' may tell us whether or not an instance will support the reset behavior. TBH, I don't think the underlying issue isn't that the stream supports the reset function- it's an expectation declared in the documentation of the InputSource class:
*
* <p>An InputSource object belongs to the application: the SAX parser
* shall never modify it in any way (it may modify a copy if
* necessary). However, standard processing of both byte and
* character streams is to close them on as part of end-of-parse cleanup,
* so applications should not attempt to re-use such streams after they
* have been handed to a parser. </p>
http://developer.classpath.org/doc/org/xml/sax/InputSource-source.html
I have not tested it, but I would assume that calling reset() on a closed InputStream would result in an IOException. The documentation on InputStream does not explicitly define this behavior, so it would need to be verified.
To get a more granular solution, I think we'd need to dig into the parsing behavior and figure out where the stream is being closed at. That may provide insight into ways we can influence the parser or the InputSource to change the behavior.
from antisamy.
I don't expect AntiSamy policies to get very long (a few K at most). As such, I suggest we make a copy in memory of the entire thing at the very start (e.g., a StringBuffer or whatever). And then turn that into a standard input stream we use. We then parse it, and if we have to parse it again, we create another input stream for it, and do it again. We then make sure we always close our internal streams. And then also close the original stream provided to use by the caller. I think this will simplify things.
from antisamy.
@gerardocanedo - please rebase again before issuing a pull request as I've checked in a number of changes, including more just now. This will minimize merge pain.
@kwwall - I added some info in the 1.6.2 branch to the README and the Policy methods related to disabling schema validation to indicate they are immediately deprecated and we plan to make them 'go away' in mid/late 2022 in the 1.7 release. Let me know what you think about how I've described this.
from antisamy.
@davewichers , your suggestion on storing it in memory is effectively what the ByteArrayInputStream allows. By leveraging the fact that it does not implement close we can reuse the in-memory copy of the file as the byte array that is capture.
It has the added benefit of already being an InputStream, and allows the InputSource to be reused.
The only cost is to update the InputStream passed to the InputSource and the problem with the "reuse" of a Stream is mitigated.
private static Element getTopLevelElement(InputStream is) throws PolicyException {
final InputSource source = new InputSource(toByteArrayStream(is));
return getTopLevelElement(source, new Callable<InputSource>() {
@Override
public InputSource call() throws IOException {
source.getByteStream().reset();
return source;
}
});
}
private static InputStream toByteArrayStream(InputStream in) throws PolicyException {
byte[] byteArray;
try (Reader reader = new InputStreamReader(in)) {
char[] charArray = new char[8 * 1024];
StringBuilder builder = new StringBuilder();
int numCharsRead;
while ((numCharsRead = reader.read(charArray, 0, charArray.length)) != -1) {
builder.append(charArray, 0, numCharsRead);
}
byteArray = builder.toString().getBytes();
} catch (IOException ioe) {
throw new PolicyException(ioe);
}
return new ByteArrayInputStream(byteArray);
}
Note the use of the Java7 try-with-resources and the wrapping of the original input stream into an InputStreamReader. This will close the original stream once all the bytes are read.
from antisamy.
Thanks @jeremiahjstacey. I changed these methods exactly as suggested and now my original method has exactly the same 2 test case failures as the new method. But at least the error messaging around invalid schema's retains its 'better' info. We now need to track down why those two test cases are failing. Do you or @gerardocanedo have time to try to track down the cause/fix for these last two failing test cases??
from antisamy.
from antisamy.
I agree. That's why I don't intend to screw over ESAPI by changing this behavior sooner than that, unless you think we should because the ESAPI community is ready for that type of change.
from antisamy.
I won't be able to do it tonight, I apologize. I may be able to take a look tomorrow morning. Can you confirm which branch I should clone to see the test failures?
I'm assuming this is all in the 1.6.2 branch on the project, just want to verify.
from antisamy.
OK. Done! I think. The failing test cases were caused by MY bug that I introduced back in 1.6.0 that I found by adding more test cases. So my fault. ESAPI team, can you test with this 1.6.2-SNAPSHOT version from the 1.6.2 branch to make sure you are happy with how everything works before I push 1.6.2 out? Hopefully we can avoid the need for a 1.6.3 in the next few days at least :-)
from antisamy.
All tests pass.
- Cloned the antisamy repository (https://github.com/nahsra/antisamy.git)
- updated to the 1.6.2 branch:
antisamy]$ git checkout 1.6.2
- Ran
antisamy]$ mvn clean install
locally to stage artifacts in my .m2 - Updated the antisamy dependency in the esapi/pom.xml on my fork to the locally-staged 1.6.2-SNAPSHOT
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.6.2-SNAPSHOT</version>
</dependency>
- Updated the HTMLValidationRule class implementation to remove pre-wrapping of ByteArrayInputStream
- Ran
esapi]$ mvn clean test
from antisamy.
Thanks @jeremiahjstacey. Anyone else need/want to review or provide feedback before I hit publish (again)? I can't do so until tonight so you have all day before I can even get to it.
from antisamy.
from antisamy.
Related Issues (20)
- AntiSamy not detecting XSS for anchor tag HOT 10
- CssHandler test case failure on Windows HOT 5
- Incorrect 'Contributing' link on OWASP wiki page HOT 1
- Javadoc cleanup
- 2 enhancement HOT 2
- 1 enhancement with api HOT 2
- CVE-2022-24891 HOT 7
- Removing Xerces dependency? HOT 3
- Does Antisamy has support for custom css properties " --* " and css-function " var() " and how to define it in the antisamy policy file? HOT 10
- Enabled noopenerAndNoreferrerAnchors policy drops nofollow HOT 7
- Covering all cases of "rel" attribute in "anchor" tag is quite verbose HOT 3
- Investigate replacing Batik CSS HOT 1
- Dealing with Security Vulnerabilities CVE-2023-26119 HOT 13
- AntiSamy encodes unknown tags despite not being configured that way HOT 6
- GraalVM Support HOT 4
- noopenerAndNoreferrerAnchors policy directive seems disabled by default in 1.7.2 version HOT 2
- How to find if vulnerable script is present in the input HOT 8
- Is there a way to not encode certain HTML Entities? HOT 6
- antisamy:1.7.3 contains batik-css:1.16 that has CVE-2022-44729 vulnerability HOT 1
- Sanitized output for same tainted input differs from AntiSamy 1.7.3 to 1.7.4 HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from antisamy.