GithubHelp home page GithubHelp logo

madappgang / identifo Goto Github PK

View Code? Open in Web Editor NEW
62.0 7.0 9.0 37.48 MB

Universal authentication framework for web, created with go

License: MIT License

Go 53.71% Shell 0.22% Makefile 0.21% HTML 0.73% CSS 4.06% Dockerfile 0.07% JavaScript 30.05% TypeScript 9.33% SCSS 1.64%
golang user login auth authentication web-service

identifo's Introduction

description
main page and positioning

Main page

Positioning

Identifo is a cloud-native user authentication system, which provides a secure native user experience with zero development efforts and full customisation and extendability.

Key points:

  • cloud-native
  • ios native expierence
  • android native expierence
  • secure
  • web server-side rendering
  • web full client-side integration with API flow (no iframes etc)
  • distributed support with JWT token
  • OIDC support
  • one line integration

{% tabs %} {% tab title="React" %}

import identifo from 'identifo.js';

identifo.init({
    url: "https://mydomain.com:123",
    app_id: "aabbccssddd",
}).login();

{% endtab %}

{% tab title="Swift iOS" %}

identifo.init()
identiof.login()

{% endtab %}

{% tab title="Kotlin Android" %}

identifo.init()
identiof.login()

{% endtab %} {% endtabs %}

{% hint style="info" %} Identifo is proudly created and supported by MadAppGang and the community. If you are missing any integration or customisation, we can do it for you as a consulting company. {% endhint %}

identifo's People

Contributors

alyakimenko avatar beautifulie avatar compaurum avatar dependabot[bot] avatar erudenko avatar esimonov avatar hummerd avatar hummerdmag avatar mag-nikita-ks avatar marksalabutin avatar nikita-ks avatar nikitagetswif avatar sokolovstas avatar suddengunter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

identifo's Issues

Identifo Admin: Federated Identity enable toggle doesn't work

When I try to enable the "Federated Identity" via API or the UI I get this error

PANIC: runtime error: invalid memory address or nil pointer dereference
goroutine 24991 [running]:
github.com/urfave/negroni.(*Recovery).ServeHTTP.func1(0x7fb29eae51f8, 0xc0000ba0b0, 0xc0001b1680, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:159 +0xd2
panic(0x10355c0, 0x1a725e0)
	/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/madappgang/identifo/web/admin.(*Router).UpdateLoginSettings.func1(0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204b00)
	/go/src/github.com/madappgang/identifo/web/admin/settings.go:232 +0xb4
net/http.HandlerFunc.ServeHTTP(0xc0005aa070, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204b00)
	/usr/local/go/src/net/http/server.go:2049 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001f0b40, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/urfave/negroni.Wrap.func1(0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900, 0xc0008ac460)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:46 +0x4d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc000160630, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900, 0xc0008ac460)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc000160630, 0xc000160660, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/madappgang/identifo/web/admin.(*Router).Session.func1(0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900, 0xc0008ac400)
	/go/src/github.com/madappgang/identifo/web/admin/middleware.go:23 +0xe6
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc0002f00b0, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900, 0xc0008ac400)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc0002f00b0, 0xc000160648, 0x7fb29eae51f8, 0xc0000ba0c0, 0xc000204900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc000637200, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:96 +0xf1
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001f0900, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/urfave/negroni.Wrap.func1(0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac3e0)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:46 +0x4d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc000160d38, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac3e0)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc000160d38, 0xc000160df8, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/rs/cors.(*Cors).ServeHTTP(0xc00042ad20, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac3c0)
	/go/pkg/mod/github.com/rs/[email protected]/cors.go:240 +0x18f
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c20, 0xc00042ad20, 0xc000160de0, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
net/http.HandlerFunc.ServeHTTP(...)
	/usr/local/go/src/net/http/server.go:2049
github.com/madappgang/identifo/web/admin.(*Router).RemoveTrailingSlash.func1(0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac3a0)
	/go/src/github.com/madappgang/identifo/web/admin/middleware.go:86 +0x82
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0x11d5938, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac3a0)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0x11d5938, 0xc000160d98, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Static).ServeHTTP(0xc0002f5410, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac380)
	/go/pkg/mod/github.com/urfave/[email protected]/static.go:34 +0x7c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412cc0, 0xc0002f5410, 0xc000160d80, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Logger).ServeHTTP(0xc0002f4db0, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac360)
	/go/pkg/mod/github.com/urfave/[email protected]/logger.go:62 +0x8a
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c60, 0xc0002f4db0, 0xc000160d68, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Recovery).ServeHTTP(0xc0001b1680, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100, 0xc0008ac340)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:193 +0x8c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412ca0, 0xc0001b1680, 0xc000160d50, 0x7fb29eae51f8, 0xc0000ba0b0, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc0002f5470, 0x1423830, 0xc00080a000, 0xc000204100)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:96 +0xf1
github.com/madappgang/identifo/web/admin.(*Router).ServeHTTP(0xc0004f5c70, 0x1423830, 0xc00080a000, 0xc000204100)
	/go/src/github.com/madappgang/identifo/web/admin/router.go:153 +0x4d
net/http.StripPrefix.func1(0x1423830, 0xc00080a000, 0xc00061bf00)
	/usr/local/go/src/net/http/server.go:2092 +0x234
net/http.HandlerFunc.ServeHTTP(0xc000183050, 0x1423830, 0xc00080a000, 0xc00061bf00)
	/usr/local/go/src/net/http/server.go:2049 +0x44
net/http.(*ServeMux).ServeHTTP(0xc000078340, 0x1423830, 0xc00080a000, 0xc00061bf00)
	/usr/local/go/src/net/http/server.go:2428 +0x1ad
github.com/madappgang/identifo/web.(*Router).ServeHTTP(0xc00073c900, 0x1423830, 0xc00080a000, 0xc00061bf00)
	/go/src/github.com/madappgang/identifo/web/router.go:95 +0x4d
net/http.serverHandler.ServeHTTP(0xc00080a2a0, 0x1423830, 0xc00080a000, 0xc00061bf00)
	/usr/local/go/src/net/http/server.go:2867 +0xa3
net/http.(*conn).serve(0xc0000c3220, 0x1428620, 0xc0007a4c00)
	/usr/local/go/src/net/http/server.go:1932 +0x8cd
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2993 +0x39b

And here is the payload object:

{
    "login_with": {
        "username": true,
        "phone": true,
        "federated": true
    },
    "tfa_type": "sms"
}

And here is the API spec:

PUT {adminPanelUrl}/admin/settings/login

Also, please have a look at this video explaining the situation:
https://www.loom.com/share/2a30ef4575e843509cd3219471ed4b56

Identifo server-config.yaml file: Latest working config doc

Here is an example of working configuration with latest Identifo version. Needs an update in docs and sample code:

general:
    host: http://server
    port: 80
    issuer: http://server
    algorithm: es256
adminAccount:
    loginEnvName: IDENTIFO_ADMIN_LOGIN
    passwordEnvName: IDENTIFO_ADMIN_PASSWORD
storage:
    appStorage:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
    userStorage:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
    tokenStorage:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
    tokenBlacklist:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
    verificationCodeStorage:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
    inviteStorage:
        type: mongodb
        mongo:
            connection: mongodb+srv://user:[email protected]/database
            database: database
sessionStorage:
    type: memory
    sessionDuration: 300
static:
    type: s3
    s3:
        region: ap-southeast-2
        bucket: bucket-name
        folder: ./static
    serveAdminPanel: true
services:
    email:
        type: ses
        ses:
            region: ap-southeast-2
            sender: [email protected]
    sms:
        type: twilio
        twilio:
            accountSid: account-sid
            authToken: auth-token
            serviceSid: service-sid
login:
    loginWith:
        username: true
        phone: true
        email: true
        federated: false
    tfaType: sms
keyStorage:
    type: s3
    s3:
        region: ap-southeast-2
        bucket: bucket-name
        private_key_key: ./keys/rsa_private.pem
        public_key_key: ./keys/rsa_public.pem
config:
    type: s3
    s3:
        region: ap-southeast-2
        bucket: bucket-name
        key: server-config.yaml
logger:
    file_name: logs

Web Login: Incorrect password message is misleading

As a user, I want to see a message like "Invalid credentials" when I enter the wrong password. Instead, I see "User not found" which is misleading.

image

Here is the error message for the same request:

API_ROUTER: 2021/09/17 03:08:47 router.go:152: api error: error.api.request.incorrect_login_or_password (status=401). Details: User not found. . Where: LoginWithPassword.CheckPassword.
[negroni] 2021-09-17T03:08:47Z | 401 |   106.544718ms | identifo.dev.evergen.technology | POST /auth/login
A

Identifo Configuration: Error loop in reading the configuration

In Identifo v2.1.2, when the Identifo container is spinning up with an AWS IAM user, it use to get the configurations and parse them from S3 using this key in the config YAML file:

config:
    type: s3
    s3:
        region: ap-southeast-2
        bucket: identifo-dev
        key: server-config.yaml

But in v2.1.3 this config has been removed from "parser" but the application is expecting to get this piece of the configuration parsed properly. Please see the below code that is checking for that config:

image

So, basically, there is no way to get away from the above check. The config parser won't let you set the config key and the above code expects to see the config key.

Identifo Web Login: 500 error when trying to login with email and password

When I try to login with Email & Password pair, I'm seeing a 500 error in API response:

PANIC: runtime error: invalid memory address or nil pointer dereference
goroutine 940 [running]:
github.com/urfave/negroni.(*Recovery).ServeHTTP.func1(0x7fb45fefd4b8, 0xc000218068, 0xc0001fc1e0, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:159 +0xd2
panic(0x10355c0, 0x1a725e0)
	/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/casbin/casbin/persist.LoadPolicyLine(0xc0005c61e4, 0x15, 0xc000289950)
	/go/pkg/mod/github.com/casbin/[email protected]/persist/adapter.go:36 +0x223
github.com/qiangmzsx/string-adapter.(*Adapter).LoadPolicy(0xc000142e20, 0xc000289950, 0x109faa0, 0x1099b00)
	/go/pkg/mod/github.com/qiangmzsx/[email protected]/adapter.go:48 +0xd3
github.com/casbin/casbin.(*Enforcer).LoadPolicy(0xc000267180, 0x7fb45ff03658, 0xc000142e20)
	/go/pkg/mod/github.com/casbin/[email protected]/enforcer.go:214 +0x53
github.com/casbin/casbin.(*Enforcer).InitWithModelAndAdapter(0xc000267180, 0xc000289950, 0x7fb45ff03658, 0xc000142e20)
	/go/pkg/mod/github.com/casbin/[email protected]/enforcer.go:128 +0x2d7
github.com/casbin/casbin.NewEnforcer(0xc00089af10, 0x2, 0x2, 0xc000289950)
	/go/pkg/mod/github.com/casbin/[email protected]/enforcer.go:81 +0x2cb
github.com/madappgang/identifo/web/authorization.(*Authorizer).initInternalAuthorizer(0xc000674020, 0xc000834978, 0x18, 0xc000834990, 0x18, 0x1, 0xc000839b34, 0x5, 0xc0000a8b40, 0x2d, ...)
	/go/src/github.com/madappgang/identifo/web/authorization/authorization.go:147 +0x258
github.com/madappgang/identifo/web/authorization.(*Authorizer).authorizeInternal(0xc000674020, 0xc000834978, 0x18, 0xc000834990, 0x18, 0x1, 0xc000839b34, 0x5, 0xc0000a8b40, 0x2d, ...)
	/go/src/github.com/madappgang/identifo/web/authorization/authorization.go:114 +0x65
github.com/madappgang/identifo/web/authorization.(*Authorizer).Authorize(0xc000674020, 0xc000834978, 0x18, 0xc000834990, 0x18, 0x1, 0xc000839b34, 0x5, 0xc0000a8b40, 0x2d, ...)
	/go/src/github.com/madappgang/identifo/web/authorization/authorization.go:46 +0xfc
github.com/madappgang/identifo/web/api.(*Router).LoginWithPassword.func1(0x7fb45fefd4b8, 0xc000218068, 0xc00020bb00)
	/go/src/github.com/madappgang/identifo/web/api/login.go:150 +0x4d8
net/http.HandlerFunc.ServeHTTP(0xc000347b50, 0x7fb45fefd4b8, 0xc000218068, 0xc00020bb00)
	/usr/local/go/src/net/http/server.go:2049 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001e6600, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b900)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/urfave/negroni.Wrap.func1(0x7fb45fefd4b8, 0xc000218068, 0xc00020b900, 0xc000599400)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:46 +0x4d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc00000e990, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b900, 0xc000599400)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc00000e990, 0xc00000ea98, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/madappgang/identifo/web/api.(*Router).SignatureHandler.func1(0x7fb45fefd4b8, 0xc000218068, 0xc00020b900, 0xc0005993e0)
	/go/src/github.com/madappgang/identifo/web/api/appsecret.go:80 +0x6ad
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc000347b00, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b900, 0xc0005993e0)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc000347b00, 0xc00000ea80, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
net/http.HandlerFunc.ServeHTTP(...)
	/usr/local/go/src/net/http/server.go:2049
github.com/madappgang/identifo/web/api.(*Router).AppID.func1(0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599380)
	/go/src/github.com/madappgang/identifo/web/api/app_middleware.go:35 +0x32d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc0003479e0, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599380)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc0003479e0, 0xc00000ea50, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/rs/cors.(*Cors).ServeHTTP(0xc000666000, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599360)
	/go/pkg/mod/github.com/rs/[email protected]/cors.go:240 +0x18f
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c20, 0xc000666000, 0xc00000ea38, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
net/http.HandlerFunc.ServeHTTP(...)
	/usr/local/go/src/net/http/server.go:2049
github.com/madappgang/identifo/web/api.(*Router).RemoveTrailingSlash.func1(0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599340)
	/go/src/github.com/madappgang/identifo/web/api/app_middleware.go:41 +0x82
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0x11d5940, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599340)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0x11d5940, 0xc00000ea08, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Static).ServeHTTP(0xc0006eacc0, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599320)
	/go/pkg/mod/github.com/urfave/[email protected]/static.go:34 +0x7c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412cc0, 0xc0006eacc0, 0xc00000e9f0, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Logger).ServeHTTP(0xc0006ea720, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc000599300)
	/go/pkg/mod/github.com/urfave/[email protected]/logger.go:62 +0x8a
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c60, 0xc0006ea720, 0xc00000e9c0, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Recovery).ServeHTTP(0xc0001fc1e0, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800, 0xc0005992e0)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:193 +0x8c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412ca0, 0xc0001fc1e0, 0xc00000e9a8, 0x7fb45fefd4b8, 0xc000218068, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc0006eb080, 0x1423830, 0xc000018460, 0xc00020b800)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:96 +0xf1
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001e6540, 0x1423830, 0xc000018460, 0xc00020b600)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/madappgang/identifo/web/api.(*Router).ServeHTTP(0xc00079c000, 0x1423830, 0xc000018460, 0xc00020b600)
	/go/src/github.com/madappgang/identifo/web/api/router.go:38 +0x4d
net/http.(*ServeMux).ServeHTTP(0xc0005ea1c0, 0x1423830, 0xc000018460, 0xc00020b600)
	/usr/local/go/src/net/http/server.go:2428 +0x1ad
github.com/madappgang/identifo/web.(*Router).ServeHTTP(0xc00043def0, 0x1423830, 0xc000018460, 0xc00020b600)
	/go/src/github.com/madappgang/identifo/web/router.go:95 +0x4d
net/http.serverHandler.ServeHTTP(0xc0004ec1c0, 0x1423830, 0xc000018460, 0xc00020b600)
	/usr/local/go/src/net/http/server.go:2867 +0xa3
net/http.(*conn).serve(0xc0002db860, 0x1428620, 0xc000331000)
	/usr/local/go/src/net/http/server.go:1932 +0x8cd
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2993 +0x39b

Here is a breakdown on request and headers:
image

Demo in this video:
https://www.loom.com/share/df2886204d8941539b6a795b0792216b

Identifo Admin: Public key is not recognized from server config file

@jack Rudenko found the issue. The problem is not with the public/private key pair. Itโ€™s with the settings parser. The public_key_key is removed from settings:
image

https://www.loom.com/share/5e8bd08fb8c34887a037ae48138378cc

Itโ€™s been removed in this commit:
d1a92bb

So, currently, there is no way to introduce or generate a public key to Identifo.

Also, when I try "Generate Key" it also doesn't work:
image

Here's the response:

{
    "error": "error creating PEM: x509: unsupported public key type: <nil>",
    "code": 500
}

Web Login: Feature Request: 2FA send the code again

When users put their user/pass pair, they're asked to input their 2FA like so:
image

But there is no option to resend the code in cases in which they haven't got the code. So, it looks necessary to have a "Send the code again" button somewhere up there โ˜๏ธ

Identifo Admin: Key is invalid error when trying to login

This issue is happening on v2.1.2
The public and private key pair is identified and showed in the admin panel but when I try to login I'm prompted with an error. Please find more information in this video:
https://www.loom.com/share/61f305574b374f3eb4a05c101fcb2986

2021/09/16 00:12:57 s3 config poll watcher checking the config file ...
API_ROUTER: 2021/09/16 00:12:59 router.go:152: api error: api.internal_server_error (status=500). Details: key is invalid. Where: LoginWithPassword.LoginFlowError.
[negroni] 2021-09-16T00:12:59Z | 500 |   103.344744ms | identifo.dev.evergen.technology | POST /auth/login
A

error creating PEM: x509: unsupported public key type: <nil>

This is happening on Identifo v2.1.1. A 500 error happens when logging in to the admin panel. After logging into the admin panel an error snack bar will appear like so:
image

Here is a complete request and response:

{
    "error": "error creating PEM: x509: unsupported public key type: <nil>",
    "code": 500
}

Request:
image

Response Headers:
image

Request Headers:
image

Query Parameters:
image

Identifo Admin: Edit login types not working for email

The login with email boolean settings cannot be set to false neither from UI nor server-config.yaml file. Please find more details in this video:
https://www.loom.com/share/a3b5cfe74d66428782a2807880c715d0

Also, here is the detailed error message for UI:

PANIC: runtime error: invalid memory address or nil pointer dereference
goroutine 619 [running]:
github.com/urfave/negroni.(*Recovery).ServeHTTP.func1(0x7fae7b9deb38, 0xc000010040, 0xc00017c320, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:159 +0xd2
panic(0x10355c0, 0x1a725e0)
	/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/madappgang/identifo/web/admin.(*Router).UpdateLoginSettings.func1(0x7fae7b9deb38, 0xc000010058, 0xc00067ad00)
	/go/src/github.com/madappgang/identifo/web/admin/settings.go:232 +0xb4
net/http.HandlerFunc.ServeHTTP(0xc000806070, 0x7fae7b9deb38, 0xc000010058, 0xc00067ad00)
	/usr/local/go/src/net/http/server.go:2049 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc00026a840, 0x7fae7b9deb38, 0xc000010058, 0xc00067ab00)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/urfave/negroni.Wrap.func1(0x7fae7b9deb38, 0xc000010058, 0xc00067ab00, 0xc000679600)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:46 +0x4d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc0003cacf0, 0x7fae7b9deb38, 0xc000010058, 0xc00067ab00, 0xc000679600)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc0003cacf0, 0xc0003cad20, 0x7fae7b9deb38, 0xc000010058, 0xc00067ab00)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/madappgang/identifo/web/admin.(*Router).Session.func1(0x7fae7b9deb38, 0xc000010058, 0xc00067ab00, 0xc0006795a0)
	/go/src/github.com/madappgang/identifo/web/admin/middleware.go:23 +0xe6
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc0001b7aa0, 0x7fae7b9deb38, 0xc000010058, 0xc00067ab00, 0xc0006795a0)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc0001b7aa0, 0xc0003cad08, 0x7fae7b9deb38, 0xc000010058, 0xc00067ab00)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc00082f200, 0x7fae7b9deb38, 0xc000010040, 0xc00067ab00)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:96 +0xf1
github.com/gorilla/mux.(*Router).ServeHTTP(0xc00026a600, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/gorilla/[email protected]/mux.go:212 +0xd3
github.com/urfave/negroni.Wrap.func1(0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679580)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:46 +0x4d
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0xc0003cb3f8, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679580)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0xc0003cb3f8, 0xc0003cb488, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/rs/cors.(*Cors).ServeHTTP(0xc000299860, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679560)
	/go/pkg/mod/github.com/rs/[email protected]/cors.go:240 +0x18f
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c20, 0xc000299860, 0xc0003cb470, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
net/http.HandlerFunc.ServeHTTP(...)
	/usr/local/go/src/net/http/server.go:2049
github.com/madappgang/identifo/web/admin.(*Router).RemoveTrailingSlash.func1(0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679540)
	/go/src/github.com/madappgang/identifo/web/admin/middleware.go:86 +0x82
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0x11d5938, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679540)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:29 +0x4e
github.com/urfave/negroni.middleware.ServeHTTP(0x14145e0, 0x11d5938, 0xc0003cb458, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Static).ServeHTTP(0xc00016d0b0, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679520)
	/go/pkg/mod/github.com/urfave/[email protected]/static.go:34 +0x7c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412cc0, 0xc00016d0b0, 0xc0003cb440, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Logger).ServeHTTP(0xc00016c960, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc000679500)
	/go/pkg/mod/github.com/urfave/[email protected]/logger.go:62 +0x8a
github.com/urfave/negroni.middleware.ServeHTTP(0x1412c60, 0xc00016c960, 0xc0003cb428, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Recovery).ServeHTTP(0xc00017c320, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900, 0xc0006794e0)
	/go/pkg/mod/github.com/urfave/[email protected]/recovery.go:193 +0x8c
github.com/urfave/negroni.middleware.ServeHTTP(0x1412ca0, 0xc00017c320, 0xc0003cb410, 0x7fae7b9deb38, 0xc000010040, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:38 +0x9c
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc00016d110, 0x1423830, 0xc0001922a0, 0xc00067a900)
	/go/pkg/mod/github.com/urfave/[email protected]/negroni.go:96 +0xf1
github.com/madappgang/identifo/web/admin.(*Router).ServeHTTP(0xc0001e8c40, 0x1423830, 0xc0001922a0, 0xc00067a900)
	/go/src/github.com/madappgang/identifo/web/admin/router.go:153 +0x4d
net/http.StripPrefix.func1(0x1423830, 0xc0001922a0, 0xc000199700)
	/usr/local/go/src/net/http/server.go:2092 +0x234
net/http.HandlerFunc.ServeHTTP(0xc0002775c0, 0x1423830, 0xc0001922a0, 0xc000199700)
	/usr/local/go/src/net/http/server.go:2049 +0x44
net/http.(*ServeMux).ServeHTTP(0xc0003f1500, 0x1423830, 0xc0001922a0, 0xc000199700)
	/usr/local/go/src/net/http/server.go:2428 +0x1ad
github.com/madappgang/identifo/web.(*Router).ServeHTTP(0xc0003cf4d0, 0x1423830, 0xc0001922a0, 0xc000199700)
	/go/src/github.com/madappgang/identifo/web/router.go:95 +0x4d
net/http.serverHandler.ServeHTTP(0xc0001b82a0, 0x1423830, 0xc0001922a0, 0xc000199700)
	/usr/local/go/src/net/http/server.go:2867 +0xa3
net/http.(*conn).serve(0xc00076a000, 0x1428620, 0xc00013ca40)
	/usr/local/go/src/net/http/server.go:1932 +0x8cd
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2993 +0x39b`

And here is the error message from helm deployment:

Error: UPGRADE FAILED: cannot patch "evergen-auth-dev" with kind Deployment:  "" is invalid: patch: Invalid value: "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{\"deployment.kubernetes.io/revision\":\"5\",\"meta.helm.sh/release-name\":\"evergen-auth-dev\",\"meta.helm.sh/release-namespace\":\"dev\"},\"creationTimestamp\":\"2021-08-16T02:19:29Z\",\"generation\":5,\"labels\":{\"app\":\"evergen-auth-dev\",\"app.kubernetes.io/managed-by\":\"Helm\"},\"managedFields\":[{\"manager\":\"Go-http-client\",\"operation\":\"Update\",\"apiVersion\":\"apps/v1\",\"time\":\"2021-08-17T07:15:47Z\",\"fieldsType\":\"FieldsV1\",\"fieldsV1\":{\"f:metadata\":{\"f:annotations\":{\".\":{},\"f:meta.helm.sh/release-name\":{},\"f:meta.helm.sh/release-namespace\":{}},\"f:labels\":{\".\":{},\"f:app\":{},\"f:app.kubernetes.io/managed-by\":{}}},\"f:spec\":{\"f:progressDeadlineSeconds\":{},\"f:replicas\":{},\"f:revisionHistoryLimit\":{},\"f:selector\":{},\"f:strategy\":{\"f:rollingUpdate\":{\".\":{},\"f:maxSurge\":{},\"f:maxUnavailable\":{}},\"f:type\":{}},\"f:template\":{\"f:metadata\":{\"f:labels\":{\".\":{},\"f:app\":{}}},\"f:spec\":{\"f:containers\":{\"k:{\\\"name\\\":\\\"evergen-auth\\\"}\":{\".\":{},\"f:args\":{},\"f:command\":{},\"f:env\":{\".\":{},\"k:{\\\"name\\\":\\\"AWS_ACCESS_KEY_ID\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"AWS_SECRET_ACCESS_KEY\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"CONTAINER_IMAGE_TAG\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"IDENTIFO_ADMIN_LOGIN\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"IDENTIFO_ADMIN_PASSWORD\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"IDENTIFO_ARG\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}}},\"f:image\":{},\"f:imagePullPolicy\":{},\"f:livenessProbe\":{\".\":{},\"f:failureThreshold\":{},\"f:httpGet\":{\".\":{},\"f:path\":{},\"f:port\":{},\"f:scheme\":{}},\"f:initialDelaySeconds\":{},\"f:periodSeconds\":{},\"f:successThreshold\":{},\"f:timeoutSeconds\":{}},\"f:name\":{},\"f:readinessProbe\":{\".\":{},\"f:failureThreshold\":{},\"f:httpGet\":{\".\":{},\"f:path\":{},\"f:port\":{},\"f:scheme\":{}},\"f:initialDelaySeconds\":{},\"f:periodSeconds\":{},\"f:successThreshold\":{},\"f:timeoutSeconds\":{}},\"f:resources\":{},\"f:terminationMessagePath\":{},\"f:terminationMessagePolicy\":{},\"f:workingDir\":{}}},\"f:dnsPolicy\":{},\"f:restartPolicy\":{},\"f:schedulerName\":{},\"f:securityContext\":{},\"f:terminationGracePeriodSeconds\":{}}}}}},{\"manager\":\"kube-controller-manager\",\"operation\":\"Update\",\"apiVersion\":\"apps/v1\",\"time\":\"2021-08-17T07:16:17Z\",\"fieldsType\":\"FieldsV1\",\"fieldsV1\":{\"f:metadata\":{\"f:annotations\":{\"f:deployment.kubernetes.io/revision\":{}}},\"f:status\":{\"f:availableReplicas\":{},\"f:conditions\":{\".\":{},\"k:{\\\"type\\\":\\\"Available\\\"}\":{\".\":{},\"f:lastTransitionTime\":{},\"f:lastUpdateTime\":{},\"f:message\":{},\"f:reason\":{},\"f:status\":{},\"f:type\":{}},\"k:{\\\"type\\\":\\\"Progressing\\\"}\":{\".\":{},\"f:lastTransitionTime\":{},\"f:lastUpdateTime\":{},\"f:message\":{},\"f:reason\":{},\"f:status\":{},\"f:type\":{}}},\"f:observedGeneration\":{},\"f:readyReplicas\":{},\"f:replicas\":{},\"f:updatedReplicas\":{}}}}],\"name\":\"evergen-auth-dev\",\"namespace\":\"dev\",\"resourceVersion\":\"10733074\",\"uid\":\"bf8f240f-8f03-4811-a307-c89f85b0f38d\"},\"spec\":{\"progressDeadlineSeconds\":600,\"replicas\":1,\"revisionHistoryLimit\":10,\"selector\":{\"matchLabels\":{\"app\":\"evergen-auth-dev\"}},\"strategy\":{\"type\":\"RollingUpdate\",\"rollingUpdate\":{\"maxUnavailable\":\"25%!\(MISSING)",\"maxSurge\":\"25%!\(MISSING)"}},\"template\":{\"metadata\":{\"creationTimestamp\":null,\"labels\":{\"app\":\"evergen-auth-dev\"}},\"spec\":{\"containers\":[{\"args\":[\"$(IDENTIFO_ARG)\"],\"command\":[\"./identifo\"],\"env\":[{\"name\":\"IDENTIFO_ADMIN_LOGIN\",\"value\":\"$IDENTIFO_ADMIN_PASSWORD\"},{\"name\":\"IDENTIFO_ADMIN_PASSWORD\",\"value\":\"$IDENTIFO_ADMIN_PASSWORD\"},{\"name\":\"CONTAINER_IMAGE_TAG\",\"value\":9522035},{\"name\":\"AWS_ACCESS_KEY_ID\",\"value\":\"AKIAV5O3VXQPSPTAF7IL\"},{\"name\":\"AWS_SECRET_ACCESS_KEY\",\"value\":\"$AWS_SECRET_DEV\"},{\"name\":\"IDENTIFO_ARG\",\"value\":\"--config=s3://ap-southeast-2@identifo-dev/server-config.yaml\"}],\"image\":\"madappgangd/identifo\",\"imagePullPolicy\":\"Always\",\"livenessProbe\":{\"httpGet\":{\"path\":\"/ping\",\"port\":80},\"initialDelaySeconds\":10,\"periodSeconds\":10},\"name\":\"evergen-auth\",\"readinessProbe\":{\"httpGet\":{\"path\":\"/ping\",\"port\":80},\"initialDelaySeconds\":20,\"periodSeconds\":10},\"resources\":{},\"workingDir\":\"/root\"}],\"dnsPolicy\":\"ClusterFirst\",\"restartPolicy\":\"Always\",\"schedulerName\":\"default-scheduler\",\"securityContext\":{},\"terminationGracePeriodSeconds\":30}}},\"status\":{\"observedGeneration\":5,\"replicas\":1,\"updatedReplicas\":1,\"readyReplicas\":1,\"availableReplicas\":1,\"conditions\":[{\"type\":\"Available\",\"status\":\"True\",\"lastUpdateTime\":\"2021-08-17T07:09:37Z\",\"lastTransitionTime\":\"2021-08-17T07:09:37Z\",\"reason\":\"MinimumReplicasAvailable\",\"message\":\"Deployment has minimum availability.\"},{\"type\":\"Progressing\",\"status\":\"True\",\"lastUpdateTime\":\"2021-08-17T07:16:18Z\",\"lastTransitionTime\":\"2021-08-16T02:43:52Z\",\"reason\":\"NewReplicaSetAvailable\",\"message\":\"ReplicaSet \\\"evergen-auth-dev-6f444cd59c\\\" has successfully progressed.\"}]}}": v1.Deployment.Spec: v1.DeploymentSpec.Template: v1.PodTemplateSpec.Spec: v1.PodSpec.Containers: []v1.Container: v1.Container.Env: []v1.EnvVar: v1.EnvVar.Value: ReadString: expects " or n, but found 9, error found in #10 byte of ...|,"value":9522035},{"|..., bigger context ...|":"$IDENTIFO_ADMIN_PASSWORD"},{"name":"CONTAINER_IMAGE_TAG","value":9522035},{"name":"AWS_ACCESS_KEY_ID","value":"AKIAV|...

Possible to login as another user

If there is the first user with login, for example
Username123 and another user with login username123,
One of them will never been able to enter his account.

useless replace directive in go.mod

It seems that MadAppGang/identifo does not depend on github.com/sfreiberg/gotwilio any more, both directly and indirectly.
So, replace directive left in go.mod makes no sense. Should it be dropped?

replace github.com/sfreiberg/gotwilio => github.com/MadAppGang/gotwilio v0.0.0-20210820024906-f91dd2ebe762

Identifo allow registration not reflected on the web login page

If we disable these 2 options from an application, we are disabling the user access to any signup or registration views:

  1. Allow Registration
  2. Allow Anonymous Registration

But in this case, although I disabled them like so:
image

I still can see the signup link on the web login page:
image

Actual behavior:
The Don't have an account? Sign Up text is visible on the web login page.

Expected behavior:
The text Don't have an account? Sign Up should not be visible to the user as the registration is not allowed.

Add ability to choose login way

Many ways to login exist in the application at the moment. It would be great to add an ability to choose specific ways to login in the application

Identifo Admin: Casbin authorization UI update doesn't work

This is an issue with the admin panel.

When I try to populate the Casbin authorization model for the application, it doesn't send the policy with the API call. Haven't checked the API but there is definitely an issue with the UI so far. Please have a look at this video:

https://www.loom.com/share/f0d5f99452684687b610c5bc171273e3

{
    "id": "_ID_",
    "secret": "secret",
    "active": true,
    "name": "SYSTEM",
    "description": "SYSTEM DESCRIPTION",
    "type": "web",
    "redirect_urls": [
        "https://domain.com"
    ],
    "tfa_status": "mandaroty",
    "debug_tfa_code": "1234",
    "registration_forbidden": true,
    "authorization_way": "internal",
    "authorization_model": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == \"root\"",
    "roles_whitelist": [
        "admin",
        "fleet_manager",
        "asset_manager"
    ],
    "new_user_default_role": "fleet_manager",
    "token_payload_service_plugin_settings": {},
    "token_payload_service_http_settings": {},
    "authorization_policy": "" ---->> THIS VALUE IS NOT BEING SET BY THE UI
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.