ring-clojure / ring-defaults Goto Github PK
View Code? Open in Web Editor NEWA library to provide sensible Ring middleware defaults
License: MIT License
A library to provide sensible Ring middleware defaults
License: MIT License
site-defaults
enables both the session middleware and ring-anti-forgery. The session middleware leaks sessions by default and ring-anti-forgery uses sessions to store the anti-CSRF-tokens it creates. Thus, even if you don't use sessions yourself, ring-anti-forgery creates a session for every user and these sessions are never removed.
I'm not sure if there's a backwards-compatible way to fix it, or if it needs to be fixed in the first place, but I think it would be a good idea to at least document this.
White source utility flagged following issue in commons-io, which is a library used in ring-core:
In Apache Commons IO before 2.7, When invoking the method FileNameUtils.normalize with an improper input string, like "//../foo", or "\..\foo", the result would be the same value, thus possibly providing access to files in the parent directory, but not further above (thus "limited" path traversal), if the calling code would use the result to construct a path value.
Suggested fix by the utility:
Upgrade to version commons-io:commons-io:2.7
or
Replace or update the following files: FilenameUtilsTestCase.java, FilenameUtils.java
Hi All,
I'm running into this issue trying to run a test via jenkins pipeline line job. i'm getting the below error with connection to github. I'm making a api call to get the sha of a file on github. Im not seeing this error when I run the same test using vscode.
java.lang.ClassCastException: io.restassured.internal.RestAssuredResponseOptionsImpl incompatible with io.restassured.response.ResponseOptions
thank you!
Hi, I have a problem 'requiring' this module into my project. I wish to migrate from compojure.handler
(deprecated since 1.2 I believe) to ring-defaults.
I'm using openjdk-8 and running Ubuntu 16.04 version 32 bit.
$ uname -a
Linux why 4.4.0-128-generic #154-Ubuntu SMP Fri May 25 14:14:58 UTC 2018 i686 i686 i686 GNU/Linux
My dependencies in project.clj
file
:dependencies [[org.clojure/clojure "1.8.0"]
[ring/ring-core "1.6.3"]
[ring/ring-jetty-adapter "1.6.3"]
[ring/ring-devel "1.7.0-RC1"]
[hiccup "1.0.5"]
[compojure "1.6.1"]
[ring/ring-defaults "0.3.2"]
[org.clojure/tools.cli "0.3.7"]
[alxlit/autoclave "0.2.0"]
[org.clojure/java.jdbc "0.7.7"]
[org.xerial/sqlite-jdbc "3.23.1"]]
Here is the my project stacktrace
$ lein run
Compiling pragma.core
2018-07-20 18:30:28.527:INFO::main: Logging initialized @2701ms
java.lang.ClassNotFoundException: org.apache.commons.codec.binary.Base32, compiling:(random.clj:1:1)
Exception in thread "main" java.lang.ClassNotFoundException: org.apache.commons.codec.binary.Base32, compiling:(random.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at ring.middleware.anti_forgery.session$loading__5569__auto____42.invoke(session.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at ring.middleware.anti_forgery$loading__5569__auto____40.invoke(anti_forgery.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:2422)
at ring.middleware.defaults$loading__5569__auto____38.invoke(defaults.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:703)
at pragma.core$loading__5569__auto____36.invoke(core.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$compile$fn__5682.invoke(core.clj:5903)
at clojure.core$compile.invokeStatic(core.clj:5903)
at clojure.core$compile.invoke(core.clj:5895)
at user$eval20$fn__29.invoke(form-init982869045496342417.clj:1)
at user$eval20.invokeStatic(form-init982869045496342417.clj:1)
at user$eval20.invoke(form-init982869045496342417.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6917)
at clojure.lang.Compiler.eval(Compiler.java:6917)
at clojure.lang.Compiler.load(Compiler.java:7379)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$init_opt.invokeStatic(main.clj:277)
at clojure.main$init_opt.invoke(main.clj:277)
at clojure.main$initialize.invokeStatic(main.clj:308)
at clojure.main$null_opt.invokeStatic(main.clj:342)
at clojure.main$null_opt.invoke(main.clj:339)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.codec.binary.Base32
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:69)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at clojure.lang.DynamicClassLoader.loadClass(DynamicClassLoader.java:77)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForNameNonLoading(RT.java:2181)
at crypto.random$loading__5569__auto____44.invoke(random.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
... 147 more
Compilation failed: Subprocess failed
wrap-defaults will take a nil response (indicating no handler has yet responded) and will return
{:headers
{"X-Content-Type-Options" "nosniff",
"X-Frame-Options" "SAMEORIGIN",
"X-XSS-Protection" "1; mode=block"}}
This appears to be picked up at some point and turned into a 200 OK. Final response as seen by curl is
< HTTP/1.1 200 OK
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< Content-Length: 0
* Server http-kit is not blacklisted
< Server: http-kit
< Date: Tue, 20 Jan 2015 13:37:02 GMT
<
* Connection #0 to host localhost left intact
This is being created from this code
(ring-defaults/wrap-defaults
(-> ring-defaults/site-defaults
(assoc :proxy true)
(assoc-in [:security :anti-forgery] false)))
Desired behaviour is nil in, nil out.
Hi,
I have some troubles to have a secure and named session cookie.
With this code:
(-> (handler/site app-routes)
(wrap-default-charset "utf-8")
(wrap-defaults (-> secure-site-defaults
(assoc :cookies true)
(assoc-in [:session :store] (cookie-store {:key (random/bytes 16)}))
(assoc-in [:session :cookie-name] "JSESSIONID")
(assoc-in [:session :cookie-attrs] {:secure true
:http-only true})))
(wrap-multipart-params)
(wrap-json-params)
(wrap-json-response)
(wrap-gzip)))```
A JSESSIONID cookie is correctly created and secured.
But in my handlers, if i set :session with som value in the response, a new cookie named ring-session is created and not secured.
I must do something wrong but can't find a solution.
Many thanks
Samuel
Hey, any reason you're aware of that the order of these two lines can't be switched?
We have a situation where it'd be convenient to use :flash
as part of the anti-forgery :error-handler
, and our options I see are to reverse the order of these two middlewares, or to use a hack like :session {:_flash XYZ}
.
Thoughts? Switching the order passed the tests, and I haven't seen any dependency issues so far.
while debuging on local machine this works fine
(ns my-app.middleware
(:require [ring.middleware.defaults :refer [api-defaults wrap-defaults]]))
(defn wrap-middleware [handler]
(-> handler
(wrap-defaults api-defaults)
)
)
Once deployed to "production"... (heroku)
2017-03-06T03:29:28.506089+00:00 heroku[router]: at=info method=POST path="/my/endpoint" host=my-app.herokuapp.com request_id=<some-id> fwd="31.13.110.127" dyno=web.1 connect=0ms service=2ms status=403
bytes=283
regression to "[compojure.handler :refer [api]] " solved the problem in production
Although its clear from the README this project is licensed under MIT, I use Dependency CI, which is currently failing as it thinks this project is unlicensed.
Adding a standard LICENSE file to the project would allow Dependency CI to automatically pick up the correct license.
Thanks ๐
Have a problem when using compojure wrap-routes to associate middleware with specific routes. Only seems to occure when using the site-defaults related config i.e. api-defaults seems to not exhibit this issue.
Appears that the wrap-defaults is blowing away the response codes when a page is not found. i.e.
$ curl -v http://localhost:3000/q
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /q HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:3000
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 21 Jan 2015 02:10:24 GMT
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Content-Length: 0
* Server Jetty(7.6.8.v20121106) is not blacklisted
< Server: Jetty(7.6.8.v20121106)
<
* Connection #0 to host localhost left intact
instead of
$ curl -v http://localhost:3000/q
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /q HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:3000
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Wed, 21 Jan 2015 02:12:49 GMT
< Content-Type: text/html;charset=UTF-8
< Content-Length: 9
* Server Jetty(7.6.8.v20121106) is not blacklisted
< Server: Jetty(7.6.8.v20121106)
<
* Connection #0 to host localhost left intact
Sorry, No%
Procedure to reporduce -
(ns cc.core.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults
api-defaults]]))
(defroutes api-routes
(GET "/api" [] "API endpoint")
(ANY "/api/order/calc" [] "Calc endpint")
(ANY "/api/order/place" [] "Place endpoint"))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/resources "/"))
(defroutes no-page
(route/not-found "Sorry, No"))
(defn mw [hdlr msg]
(fn [req]
(println msg)
(hdlr req)))
(def app
(routes (-> api-routes
(wrap-routes wrap-defaults api-defaults))
(-> app-routes
(wrap-routes wrap-defaults api-defaults))
no-page))
If you change the second wrap-defaults to use site-defaults, the problem is triggered.
As I mentioned on slack
I'd love to see if absolute redirects were not enabled by default.
The original HTTP spec that mandated this has been replaced by a newer version about 8 years ago.
This is causing problems for people running web apps behind load balancers and proxies terminating TLS.
See clj-commons/friend#4 and clj-commons/friend#5
Hi James,
The functions in this library are reminiscent to those in compojure.handler
. Would you be kind enough to explain the differences? Thanks!
Would be handy to have it out-of-the-box with api-defaults
config. What you think?
Hi- we're using ring-defaults and woul like to turn on ssl-redirects but it's not clear how to override default configuration. Does a config map get passed into ring defaults?
Didn't take me too long to find once I put time in it, but have had an enormous amount of complaints on my site that users are not staying logged in. A lot of my users come from Instagram links. When they click on the link they are logged out. Any subsequent login (via ajax) on the same browser tab and refresh will keep logging the user out.
https://github.com/ring-clojure/ring-defaults/blob/master/src/ring/middleware/defaults.clj#L45
Also do you think it may be better to put that :strict in secure-site-defaults instead of site-defaults? I feel same-site :lax would be a more sane default.
As you helped me understand in the issue on ring anti-forgery, a normal punter will try to use wrap-defaults
with site-defaults
and then add wrap-anti-forgery
, not realising that it is redundant.
How could we best add docs to indicate how to handle CSRF / XSRF validation? I guess you're suggesting a complete map of default options?
It's nice to have the config map to tweak the defaults. But some middleware have further customisations. For example, suppose I want to provide a function to wrap-anti-forgery
function. According to the docs:
This behavior can be customized further by supplying a function to the :read-token option. This function is passed the request map, and should return the anti-forgery token found in the request.
What is the best way to deal with this?
Should I set :security {:anti-forgery false}
?
(def site
(-> handler
(wrap-anti-forgery {:read-token (fn [req] (-> req :params :csrf-token))})
(wrap-defaults site-defaults-with-anti-forgery-set-to-false)))
Is there no risk of middleware getting out of order with this method?
I think most of developers will meet this issue, and solution to this issue is simple after I dig into src of both wrap-json-response and api-defaults
Is it more reasonable to set content-types default to false in api-defaults or add an option to set content-type forcefully in wrap-json-response ?
Running on heroku. Any idea what might be cause this or what I should look at?
Because of the order that site-defaults
get applied by wrap-defaults
, if you serve a static file it bypasses anti-forgery. This seems like a bad idea in general, but a concrete case where this hurts is when trying to use Sente: taoensso/sente#318
Sente requires a token, which is not present for pages using site-defaults
Based on this OWASP article, it is recommended to disable the X-XSS-Protection
header by setting X-XSS-Protection: 0
to avoid security issues in older browsers.
Currently, the default is :xss-protection {:enable? true, :mode :block}
at this line.
Also, setting :xss-protection {:enable? false}
raises an error on the pre-condition check for nil
at this line, because the code sends an empty map here ((dissoc options :enable?)
=> {}
).
I suggest updating x-headers in the ring-headers repository to enforce this solution on all the dependent repositories. However, if you would prefer only fixing this repo, I can create a PR for it.
Thanks for your attention.
When ring's content-type middleware is used and prevents other (explicitly used) content-type middleware, it can be quite hard to debug, especially because it will fail silently.
Any ideas on how to make this easier to get right by default?
See metosin/muuntaja#96 for the other side.
After deploying to wildfly, the root path "localhost:8080/app-name/" results in downloading of an empty file instead of loading the page, when ring-defaults are used.
Every other path seems to work.
Any guesses on which setting could be creating this issue?
I am creating the war using lein-immutant plugin.
WhiteSource flagged vulnerability issue in one of the dependent libraries - commons-fileupload version 1.3.3.
Following is the maven dependency tree for ring-defaults:
[INFO] +- ring:ring-defaults:jar:0.3.2:compile
[INFO] | +- (org.clojure:clojure:jar:1.5.1:compile - omitted for conflict with 1.10.1)
[INFO] | +- ring:ring-core:jar:1.6.3:compile
[INFO] | | +- (org.clojure:clojure:jar:1.5.1:compile - omitted for conflict with 1.10.1)
[INFO] | | +- ring:ring-codec:jar:1.0.1:compile
[INFO] | | | +- (org.clojure:clojure:jar:1.3.0:compile - omitted for conflict with 1.10.1)
[INFO] | | | - (commons-codec:commons-codec:jar:1.6:compile - omitted for conflict with 1.10)
[INFO] | | +- commons-io:commons-io:jar:2.5:compile
[INFO] | | +- commons-fileupload:commons-fileupload:jar:1.3.3:compile
[INFO] | | | - (commons-io:commons-io:jar:2.2:compile - omitted for conflict with 2.5)
...
This is the whitesource complain:
The class FileUploadBase in Apache Commons Fileupload before 1.4 has potential resource leak - InputStream not closed on exception.
References:
https://commons.apache.org/proper/commons-fileupload/changes-report.html
apache/commons-fileupload@5b4881d
We tried to update the version of common-fileuploads to 1.4 and run through the whitesource, and it went through successfully.
Would it be possible for you to update the version of file-uploads in "ring"? If yes, how soon can you provide updated build?
When using ring and ring-defaults to serve static html, Firefox complains in its console that
The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.
w3 suggests that utf-8 is a reasonable default. I also interpret their comments there, and on linked pages, as saying that specifying utf-8 is better than defaulting to iso-8859-1 (which the absence of a charset implies), as utf-8 is more likely to be correct in more cases.
Currently everyone using ring, even with defaults, has to set the charset, even though it will be utf-8 in the majority of cases. Would it be an improvement for ring users if ring-defaults included a middleware that appends ;charset=utf-8
to all text-based content-types (text/*, application/json, ...), when no charset has been added to the response yet?
It seems that this option and others such as :loader
and :prefer-handler?
are not configurable via defaults.
This is also an issue when attempting to configure via duct.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.