valohai / django-allauth-2fa Goto Github PK
View Code? Open in Web Editor NEWTwo-factor authentication for Django Allauth
License: Other
Two-factor authentication for Django Allauth
License: Other
pip install from pypi fails to find suitable version if python3 is used but when installing directly from github, install (and the 2fa itself) works fine under python3.
When using django-allauth and django-allauth-2fa the redirect_field_name is not passed to the 2fa login page. As you can see from the debug logs, first there is a POST to /accounts/login where the password of the user is checked and then, if required (based on BaseRequire2FAMiddleware) a GET to the two-factor-authenticate is executed - however the redirect_field_name value is gone.
Yes this is more of a problem with django-allauth but I was expecting a seamless integration. Any ideas what can be done? Right now I have my own adapter (inherited from allauth_2fa.adapter.OTPAdapter) where I can call get_login_redirect_url, however since the redirect_field value is gone, I have no way to build any logic as to where to redirect the user to.
[11/Oct/2020 12:14:35] INFO [django.server:154] "GET /admin/ HTTP/1.1" 302 0
[11/Oct/2020 12:14:35] INFO [django.server:154] "GET /admin/login/?next=/admin/ HTTP/1.1" 302 0
[11/Oct/2020 12:14:35] INFO [django.server:154] "GET /accounts/login?next=/admin/login/%3Fnext%3D/admin/ HTTP/1.1" 301 0
[11/Oct/2020 12:14:35] INFO [django.server:154] "GET /accounts/login/?next=/admin/login/%3Fnext%3D/admin/ HTTP/1.1" 200 23174
[11/Oct/2020 12:14:38] INFO [django.server:154] "POST /accounts/login/ HTTP/1.1" 302 0
[11/Oct/2020 12:14:38] INFO [django.server:154] "GET /two-factor-authenticate HTTP/1.1" 200 21569
[11/Oct/2020 12:14:43] INFO [django.server:154] "POST /two-factor-authenticate HTTP/1.1" 302 0
[11/Oct/2020 12:14:43] INFO [django.server:154] "GET / HTTP/1.1" 301 0
When using a ServiceWorker, authentication with 2FA enabled is broken. Due to some limitations it is necessary to serve the workerscript from the root of the site. In case you run something like gunicorn behind a load balancer, you will most likely just save the worker script as a template file and serve it using a template view. However, combined with allauth_2fa this causes a problem that ultimately breaks authentication for all users that have 2FA enabled.
In the OTPAdapter
(adapter.py line 22) user.id
gets stored within the session:
request.session['allauth_2fa_user_id'] = str(user.id)
The presence of allauth_2fa_user_id
in the session is then checked in the TwoFactorAuthenticate
view, (views.py line 34) . In case it's not present, the user will be redirected to the login view. Otherwise the user with allauth_2fa_user_id
will be put into kwargs and authentication will proceed.
allauth_2fa_user_id
gets cleared from the session by means of AllauthTwoFactorMiddleware
(middleware.py line 26).
When you happen to use a service worker, what will very frequently happen is:
allauth_2fa_user_id
gets stored in the user's sessionallauth_2fa_user_id
from the user's session, because the condition in middleware.py evaluates to trueallauth_2fa_user_id
is already gone and user is redirected to the login pageThis szenario is not only limited to the usage ServiceWorkers, but is triggered everytime user makes (for whatever reason) a request between logging in and entering the 2FA token that causes the condition in the middleware to evaluate to true.
I am not sure what the best alternative solution is, or if there is any evil side effect, if we do not delete allauth_2fa_user_id
at all. What do you guys suggest?
Once #4 happens, we can setup travis.
django-otp can plug into django-agent-trust with django-otp-agents, maybe there's nothing else to do here besides documenting that.
Hi!
I was thinking if we shouldn't get a release out of django-allauth-2fa that supports django 3.0?
If I can do anything just say the word :)
Cheers!
Hi,
While logged in but not yet input the 2FA code yet (so, on the authenticate page), when I try to access another URL, it directly logs me out. This is not a behavior that I want. I want to display the authenticate page again. Is there currently a way to do it ?
Thanks!
I'm trying to use this library. When i imported the views on my own urls.py using: from allauth_2fa import views
i got the following error:
File "C:\Users\User\Desktop\Heroku\github\backup\main\urls.py", line 20, in <module>
from allauth_2fa import views
File "C:\Users\User\lib\site-packages\allauth_2fa\views.py", line 23, in <module>
from django_otp.plugins.otp_static.models import StaticToken
File "C:\Users\User\lib\site-packages\django_otp\plugins\otp_static\models.py", line 11, in <module>
class StaticDevice(Device):
File "C:\Users\User\lib\site-packages\django\db\models\base.py", line 95, in __new__
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class django_otp.plugins.otp_static.models.StaticDevice doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
I don't understand if i'm doing something wrong, or the error is in the dependency module. Can anyone help me?
To include:
The documentation, in the Installation section, has a warning at the end about the admin site, and then some sample code.
The sample code has an error which can result in TFA being bypassed for the admin site. The scenario is a site where some users do not have/need TFA, but all admin users do. Using the code provided, an attacker can login with a non-admin account without TFA. Then browse directly to the admin site, and are allowed to re-login there without TFA. The redirect provided in the documentation code:
admin.site.login = login_required(admin.site.login)
does not trigger the login_required wrapper because the user logged in already. They are instead taken directly to the admin site, which provides a login view that bypassess TFA.
FIX:
Instead of wrapping with login_required, wrap with staff_member_required:
`from django.contrib.admin.views.decorators import staff_member_required
admin.site.login = staff_member_required(admin.site.login, login_url='/accounts/login')`
This will the disallow showing the admin site to anyone not logged in as an admin, preventing the attack described.
The newest version of django-otp (0.3.10) has some support for QR code views built in: https://bitbucket.org/psagers/django-otp/issues/20/
We should investigate if they can be used and if we want to require that version.
It might be reasonable to have a mode where users are required to enable 2FA, i.e. they can only access the 2FA configuration page until it's enabled.
Hi,
When logging in (having 2FA enabled), we are automatically directed on the authenticate page. Which is normal, but then if I try to click on the link to disable the 2FA, I got a 500 error AttributeError: 'AnonymousUser' object has no attribute 'totpdevice_set'
Can you reproduce the bug ?
Thanks
Currently backup codes are shown every time you go to the 2FA settings page. Most "big" websites will only show these to you once (but will let you completely regenerate them).
I'm unsure if there's a "best practice" here.
Push a release to PyPI!
The "Token" input field on the TOTPDeviceForm has autocomplete enabled. Very much a cosmetic issue but seems off?
When I attempt to visit a page that requires authentication, I get redirected to the login form with a next parameter (e.g /login/?next/my/path
). But when 2FA is enabled, this next redirect parameter is lost and I end up in the default account page.
The PR #44 seems to make sure that when I visit /two-factor-authenticate?next=/my/path
then the query parameter is passed correctly.
But I think there is still a problem before: when submitting the first user/password form, the next parameter might be passed with a POST parameter, and when this happens the next path is lost. And the default template for allauth actually passes the next as a POST parameter, and not as a url query.
See attached screenshot, I end up in accounts/profile
instead of my desired path
I am running Django 1.11, allauth 0.32 and allauth-2fa 0.4.4
After logging in and then navigating to /two_factor/setup/ and then successfully using Google Authenticator, and then navigating to /two_factor/backup_tokens/ and generating the backup tokens for an account, I logout of that account. When I try to login as that same account that was just setup to test the 2FA I am unable to login. After typing in my credentials and submitting the form then automatically navigating to /two-factor-authenticate, I get a page not found error.
Traceback:
[08/Feb/2020 23:51:25] "GET /accounts/login/?next=/memberships/profile/ HTTP/1.1" 200 11119
[08/Feb/2020 23:51:25] "GET /captcha/image/a0cfb5fe91bb6ee3caa7d92f053da85590d3bc12/ HTTP/1.1" 200 13165
(Type in the credentials then submit the form)
[08/Feb/2020 23:51:32] "POST /login/ HTTP/1.1" 302 0
Not Found: /two-factor-authenticate
[08/Feb/2020 23:51:32] "GET /two-factor-authenticate HTTP/1.1" 404 1767
Currenty almost all dependencies in setup.py
are exact. Is this really required?
"qrcode==5.1",
"django-allauth==0.23.0",
"django-otp==0.3.1",
Python package version resolving not nearly as good as npm, unfortunately.
In some cases, a user may not be able to take a picture of the QR code. In those cases, some sites display the secret for the user to enter manually into their Authentication app.
Based on the way this package generates the QR code, I suspect it will take some refactoring to make this possible.
Maybe I am misunderstanding parts of django-allauth-2fa, but I encountered the bug above when trying to remove my two factor devices via the remove form.
The function seems to work fine if I have both, a TOTP device AND backup tokens. However, if no backup tokens were created ever "static_device = self.user.staticdevice_set.get(name='backup')" fails with a "DoesNotExist" exception and the tokens remain.
So the "Delete any backup tokens" section of TOTPDeviceRemoveForm has to be protected by a try/except clause that ignores backuptokens if none are present. Therefore I propose the following change:
class TOTPDeviceRemoveForm(forms.Form):
def __init__(self, user, **kwargs):
super(TOTPDeviceRemoveForm, self).__init__(**kwargs)
self.user = user
def save(self):
# Delete any backup tokens.
try:
static_device = self.user.staticdevice_set.get(name='backup')
static_device.token_set.all().delete()
static_device.delete()
except django_otp.plugins.otp_static.models.StaticDevice.DoesNotExist:
pass
# Delete TOTP device.
device = TOTPDevice.objects.get(user=self.user)
device.delete()
As the title suggest, this project could use some unit tests.
Like most good django third party packages, we should have a simple project to help test in dev.
Allauth uses a next GET parameter to get to redirect the user back to the page he tried to visit if it was auth only and the user was not logged in. After entering login credentials the next parameter is thrown away on the two-factor-authenticate page. This shouldn't happen, because now the user is redirected to the main login page instead of the page he tried to visit.
I wanna know about status: active it or not for user . How can I get it?
FTR we liked having the master runs in-case it was going to fail in the future version, but we wouldn't fail CI on it. You can do something similar with GitHub actions: https://github.com/clokep/django-querysetsequence/blob/b5a6f06c4e83caeadcbd53816b55bc5cc0ecc03b/.github/workflows/main.yml#L40-L44
Originally posted in #110 (comment)
Currently there is no license file in the repository.
Hi, I am currently evaluating upgrading a project to Django 3 and allauth-2fa is incompatible because dropped support of django.utils.six in version 3.
https://docs.djangoproject.com/en/3.0/releases/3.0/#removed-private-python-2-compatibility-apis
Here is a traceback of running allauth-2fa with Django 3.
| File "/usr/local/lib/python3.7/site-packages/allauth_2fa/utils.py", line 8, in <module>
| from django.utils.six import BytesIO
| ModuleNotFoundError: No module named 'django.utils.six'
Any plans to migrate to six and give support to Django 3?
Thank you
Hi,
Regarding the moment after clicking "Sign In" and before completing the 2FA form:
As addressed by issue #8, I know that going to any page other than "two-factor-authenticate" takes the user out of this intermediate state (by removing the "allauth_2fa_user_id" session key).
However, as long as I stay within the "two-factor-authenticate" page, it will remain in that state until the session expires. So, I can, for example, close the page, then reopen it several days later and the 2FA form will still be there waiting for the same user to type the token.
It seems like a behavior that could be potentially exploited. Should there be a mechanism against that? Maybe the session expiry time could be set to a small value, like 5 minutes, when reaching that state, then reset to a longer value only after the flow is completed?
Thank you in advance.
I fixed this for my own website by following this stack overflow post: https://stackoverflow.com/questions/6779265/how-can-i-not-use-djangos-admin-login-view
Simply add this line:
admin.site.login = login_required(admin.site.login)
This should at least be noted in the README, and if possible be fixed in the lib itself.
Howdy,
I have an existing project that's been using django-allauth successfully for several months now. I've setup django-allauth-2fa and I was able to successfully register a device. However, when I go to login, I get the following exception and traceback. I am using a UUIDField for my User model primary key. I am requiring that all users have 2FA enabled.
Thanks for all of your work on this project!
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/login/
Django Version: 1.11.14
Python Version: 3.6.1
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'allauth_2fa.middleware.AllauthTwoFactorMiddleware',
'project.users.middleware.RequireSuperuser2FAMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'request_logging.middleware.LoggingMiddleware',
'auditlog.middleware.AuditlogMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware']
Traceback:
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/utils/deprecation.py" in __call__
142. response = self.process_response(request, response)
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/middleware.py" in process_response
58. request.session.save()
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in save
81. return self.create()
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in create
54. self.save(must_create=True)
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in save
83. obj = self.create_model_instance(data)
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py" in create_model_instance
69. session_data=self.encode(data),
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py" in encode
98. serialized = self.serializer().dumps(session_dict)
File "/Users/chromakey/.virtualenvs/project/lib/python3.6/site-packages/django/core/signing.py" in dumps
93. return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py" in dumps
238. **kw).encode(obj)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py" in encode
199. chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py" in iterencode
257. return _iterencode(o, 0)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py" in default
180. o.__class__.__name__)
Exception Type: TypeError at /accounts/login/
Exception Value: Object of type 'UUID' is not JSON serializable
Supporting U2F to be able to connect using a Yubikey would be a nice feature by integrating django-u2f or implementing it directly.
The newest version of django-allauth that was released (0.35) seems to drop support for Django < 1.11. We're using a couple of their compatibility tools that no longer exist.
In the installation section of the documentation at the very end of the page, the following method is proposed to use the allauth authentication workflow (including two-factor authentication) for access the Django admin site:
admin.site.log = staff_member_required(admin.site.login, login_url = 'accounts/login')
admin.autodiscover()
However, if a registered user, who is not a staff member logs in, the result is an ERR_TOO_MANY_REDIRECTS
error. I tried to come up with a solution by looking at the staff_member_required decorator in the django documentation but was not successful. I know it is not a django-allauth-2fa specific question, but since the above code snippet is from the documentation, I thought I give it a try.
I've seen sites that allow a user to configure multiple 2FA devices. This could be a reasonable feature to support!
It's fairly standard practice that deactivating 2FA requires you to re-authenticate with 2FA. This is related to #7.
A quick test to add django-allauth-2fa to an existing project didn't work because the view two_factor/setup
breaks on the reverse lookup of 'two-factor-qr-code'.
Our project uses pip3 with a requirements.txt file for deployment so there is no easy way to use a non-release version of the code.
Using Python 3.7.3
Relevant parts of requirements.txt:
Django~=2.2
django-allauth~=0.39
django-allauth-2fa~=0.6
The error message:
Request Method: | GET http://localhost/accounts/two_factor/setup
Django Version: 2.2.3
Exception: NoReverseMatch
Reverse for 'two-factor-qr-code' not found. 'two-factor-qr-code' is not a valid view function or pattern name.
/usr/local/lib/python3.7/site-packages/django/urls/resolvers.py in _reverse_with_prefix, line 668
It appears there are quite a few commits since the last 0.6 release which may fix thi issue already.
What is the timeline for a new release?
I am trying to use django-allauth & django-allauth-2fa in my Django app.
My django-allauth app is set uo correctly - everything is working as expected.
However, when trying to set up django-allauth-2fa I ran into some issues: Configuring a two-factor authentification at accounts/two_factor/setup/
when I scan the QR code, input the token generated and press verify the page simply reloads with a new QR code instead of leading me to the next step in the Two-Factor configuration workflow. I can't figure out what my mistake may be, as I set up everything as written in the django-allauth-2fa documentation
My Pipfile
:
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
django = "==3.0.0"
pylint = "==2.4.4"
django-crispy-forms = "==1.9"
django-allauth = "==0.42.0"
django-allauth-2fa = "==0.8"
[requires]
python_version = "3.7"
my settings.py
file
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
# Local
'users.apps.UsersConfig',
'pages.apps.PagesConfig',
#Third-party
'allauth',
'allauth.account',
'django_otp',
'django_otp.plugins.otp_totp',
'django_otp.plugins.otp_static',
'allauth_2fa',
'crispy_forms',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'allauth_2fa.middleware.AllauthTwoFactorMiddleware',
]
SITE_ID = 1
ACCOUNT_ADAPTER = 'allauth_2fa.adapter.OTPAdapter'
...
my urls.py
file
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth_2fa.urls')),
path('accounts/', include('allauth.urls')),
path('', include('pages.urls')),
]
And I also ran python manage.py migrate
Currently, the issuer for the qr code is hardcoded as part of the qr code generator view and always is the current django Site for the current request. https://github.com/percipient/django-allauth-2fa/blob/master/allauth_2fa/views.py#L206
If your site's 'name' is set some other way - for example if you're using Wagtail, which has its own site model - this is a problem, and there's not a good way to get around it without copying the entire qr generator view.
Proposed solution: add a get_issuer
method to QRCodeGeneratorView
that can be easily overridden to allow customization of the issuer name.
I'm in need of a release with the redirect to next fix, can one be made soon?
Hi,
I have a custom Middleware (source below) that should link whether two factor is required to a user model field. This is working and correctly determining when two factor should be required, and when not.
However, when a user for whom two factor is required logins, and is (correctly) redirected to the setup two factor page, the token is always coming back invalid. If a user doesn't have two factor required but setups up the two factor, the token works just fine.
Any ideas?
users.middleware.RequireTwoFactorRequiredMiddleware
from allauth_2fa.middleware import BaseRequire2FAMiddleware
class RequireTwoFactorRequiredMiddleware(BaseRequire2FAMiddleware):
def require_2fa(self, request):
return request.user.two_factor_required
Middleware ordering:
'django_otp.middleware.OTPMiddleware',
'allauth_2fa.middleware.AllauthTwoFactorMiddleware',
'users.middleware.RequireTwoFactorRequiredMiddleware'
The URLs we include are kind of a mess:
Theoretically we can just change these if people use names, but we would probably want to include redirects. It could also be nice to use a namespace.
When a URL has no name the following exception is thrown:
AttributeError: 'NoneType' object has no attribute 'startswith'
File "/usr/local/lib/python3.5/site-packages/allauth_2fa/middleware.py", line 18, in process_request
def process_request(self, request):
if not resolve(request.path).url_name.startswith( # This does not always exist
'two-factor-authenticate'):
try:
del request.session['allauth_2fa_user_id']
except KeyError:
pass
If I get time I'll make a PR. I could just add a name but an exception like this should not be thrown by a package.
I am getting a crash when trying to use the otp_email
by itself.
It appears the code calls allauth_2fa.utils.user_has_valid_totp_device()
without checking to see which device(s) are installed. Since in our demo app we just have 'django_otp.plugins.otp_email', and none of the others devices installed we get the following error relation "django_otp_totpdevice" does not exist
Adding 'django_otp.plugins.otp_totp',
to the INSTALLED_APP fixes this issue but then pushes the user through the TOTP flow instead of using email.
Given that there are other devices in the django_otp ecosystem (HOTP, Static, etc) it might be worthwhile to have user_has_valid_totp_device()
replaced by something more generic user_has_valid_device
with some logic to detect the install apps.
I don't know how a user can hit this since the setup page is protected from AnonymousUsers, but...I've seen some 500s on this page.
AttributeError: 'AnonymousUser' object has no attribute 'totpdevice_set'
File "django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
File "django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "allauth_2fa/views.py", line 158, in get
device = request.user.totpdevice_set.filter(confirmed=False).first()
File "django/utils/functional.py", line 235, in inner
return func(self._wrapped, *args)
File "django/utils/functional.py", line 235, in inner
return func(self._wrapped, *args)
django-otp supports at least TOTP, static, and HOTP. It also provides a separate packages for YubiKey and Twilio support.
We should figure out a way to make django-allauth-2fa check any appropriate 2FA systems when logging in, not just the totp devices. Some information about this is available in the docs: https://pythonhosted.org/django-otp/overview.html#plugins-and-devices
Hi,
Is there currently a way to select the pages that are protected by the 2FA ?
Thanks for your help :)
We should make it easy to override the base template (currently base.html
). Upstream allauth uses account/base.html
which by default is just a proxy for base.html
, but using that structure makes it super easy to override the base template by creating a account/base.html
file with different contents.
See https://github.com/pennersr/django-allauth/blob/master/allauth/templates/account/login.html#L1 and https://github.com/pennersr/django-allauth/blob/master/allauth/templates/account/base.html for context.
PR incoming.
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.