Giter Site home page Giter Site logo

labshare-archive / services-auth Goto Github PK

View Code? Open in Web Editor NEW
2.0 15.0 6.0 2.07 MB

OAuth2 API authorization plugin for @labshare/services and LabShare Auth

License: MIT License

JavaScript 0.33% TypeScript 99.67%
labshare jwt-validation jwt rs256 authorization-middleware oauth2 express

services-auth's Introduction

NOTE: This project has been moved to the @labshare/base-api repository

See: https://github.com/LabShare/base-api/tree/master/packages/services-auth



@labshare/services-auth

Install

npm i @labshare/services-auth

Usage

Register the component and register the configuration for the action by injecting AuthenticationBindings.AUTH_CONFIG.

Configuring the component

Options

Property Type Details
tenant string The LabShare Auth Tenant the Resource Server (API) is registered to. Example: ncats.
authUrl string The full URL to the LabShare Auth API the Resource Server (API) is registered to. Example: https://a.labshare.org
audience string The audience of the Resource Server. This is a unique identifier for the API registered on the LabShare Auth Service. It does not need match an actual API deployment host. This is required to check if a Client (application) is allowed to access the API. Example: https://my.api.com/v2. Optional.
issuer string The issuer of the Bearer Token. Use this to validate the source of the Bearer Token. Optional. Example: https://a.labshare.org/_api/ls

Bindings (optional)

To perform additional customization of token validation, you can bind Loopback Providers to the following keys:

Binding Details
AuthenticationBindings.SECRET_PROVIDER Obtains the secret used to validate the JWT signature. Not required when using tokens signed by LabShare Auth.
AuthenticationBindings.IS_REVOKED_CALLBACK_PROVIDER Used to check if the token has been revoked. For example, a request to the introspection_endpoint can check if the JWT is still valid.
AuthenticationBindings.AUDIENCE_PROVIDER Provides the value for the audience the JWT will be validated against instead of using the audience configuration assigned to AuthenticationBindings.AUTH_CONFIG.

Example IsRevokedCallbackProvider

import request = require('request-promise');

export class IsRevokedCallbackProvider {
  constructor() {}

  public async value() {
    return async (
      req: Request,
      payload,
      callback: (error: Error, isRevoked: boolean) => void
    ) => {
      try {
        // ... request to introspection endpoint
        // ... check if token is valid

        callback(null, isTokenRevoked);
      } catch (error) {
        callback(error, false);
      }
    };
  }
}

Example SecretProvider

import { jwk2pem } from 'pem-jwk';

export class SecretProvider {
  constructor(
    @inject('MyJwkService')
    private jwkService: JwkService
  ) {}

  public async value() {
    return async (
      req: Request,
      header,
      payload: any,
      cb: (err: any, secret?: any) => void
    ): Promise<void> => {
      if (!header) {
        log('Invalid JWT. No header found.');
        cb(null, null);
        return;
      }

      if (header.alg !== 'RS256' || !payload || !payload.sub) {
        cb(null, null);
        return;
      }

      try {
        const publicJWK = await this.jwkService.getPublicJWK('...');
        const secret = jwk2pem(publicJWK);

        cb(null, secret);
      } catch (error) {
        cb(null, null);
      }
    };
  }
}

Example AudienceProvider

export class SecretProvider {
  constructor(
    // Constructor can inject services used to figure out which audience to use
    @inject(RestBindings.Http.REQUEST)
    public request: Request
  ) {}

  public async value() {
    // Determine the audience the JWT should be validated against, perhaps based on a value in the API request
    return 'https://some.new.audience';
  }
}

Application Bootstrap Example

import { LbServicesAuthComponent } from '@labshare/lb-services-auth';
import { SecretProvider } from 'secret.provider';
import { AudienceProvider } from 'audience.provider';
import { IsRevokedCallbackProvider} from 'is-revoked-callback.provider';

app = new Application();
app.component(LbServicesAuthComponent);
app.bind(AuthenticationBindings.AUTH_CONFIG).to({
  authUrl: 'https://a.labshare.org/_api',
  tenant: 'my-tenant'
});

// Assign a custom JWT secret provider (optional)
app.bind(AuthenticationBindings.SECRET_PROVIDER).toProvider(SecretProvider);

// Assign a custom revoked JWT check (optional)
app.bind(AuthenticationBindings.IS_REVOKED_CALLBACK_PROVIDER).toProvider(IsRevokedCallbackProvider);

// Assign a custom audience provider (optional)
app.bind(AuthenticationBindings.IS_REVOKED_CALLBACK_PROVIDER).toProvider(AudienceProvider);

Actions

Authenticate

Inject the authenticate action into the application sequence to require the user to pass a valid bearer token and optionally validate the bearer token's scope and audience claims. Ensure the authenticate action runs before the controller methods are invoked (see the example).

Example

import {
  AuthenticationBindings,
  AuthenticateFn
} from "@labshare/lb-services-auth";

class MySequence implements SequenceHandler {
  constructor(
    @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
    @inject(SequenceActions.PARSE_PARAMS)
    protected parseParams: ParseParams,
    @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
    @inject(SequenceActions.SEND) protected send: Send,
    @inject(SequenceActions.REJECT) protected reject: Reject,

    // Inject the new authentication action
    @inject(AuthenticationBindings.AUTH_ACTION)
    protected authenticateRequest: AuthenticateFn,
  ) {}

  async handle(context: RequestContext) {
    try {
      const {request, response} = context;
      const route = this.findRoute(request);

      // Authenticate the request. We need this sequence action to run before "invoke" to ensure authentication
      // occurs first.
      await this.authenticateRequest(request as any, response as any);

      const args = await this.parseParams(request, route);
      const result = await this.invoke(route, args);
      this.send(response, result);
    } catch (error) {
      this.reject(context, error);
      return;
    }
}

User Info

Inject the user info action provider into your application sequence to assign the user's profile on request.userInfo. The profile corresponds to the response returned by LabShare Auth's OIDC user_info route.

Example

import {
  AuthenticationBindings,
  AuthenticateFn
} from "@labshare/lb-services-auth";

class MySequence implements SequenceHandler {
  constructor(
    @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
    @inject(SequenceActions.PARSE_PARAMS)
    protected parseParams: ParseParams,
    @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
    @inject(SequenceActions.SEND) protected send: Send,
    @inject(SequenceActions.REJECT) protected reject: Reject,

    // Inject the new authentication action
    @inject(AuthenticationBindings.USER_INFO_ACTION)
    protected setUserInfo: AuthenticateFn,
  ) {}

  async handle(context: RequestContext) {
    try {
      const {request, response} = context;
      const route = this.findRoute(request);

      // Set the userInfo on the request
      await this.setUserInfo(request as any, response as any);

      const args = await this.parseParams(request, route);
      const result = await this.invoke(route, args);
      this.send(response, result);
    } catch (error) {
      this.reject(context, error);
      return;
    }
}

Decorators

@authenticate

Use the @authenticate decorator for REST methods or controllers requiring authentication.

Options

Property Type Details
scopes array A list of one zero or more arbitrary Resource Scope definitions. Example: ['read:users', 'update:users']
credentialsRequired boolean Set to false to support anonymous/public requests on an endpoint. Defaults to true.

Dynamic Scopes

Dynamic path/query parameters can be injected into scope definitions using brackets. For example: [read:users:{path.id}, update:users:{query.limit}] assigned to a route such as /users/{id} would require the request's bearer token to contain a scope matching the id parameter in the route (for example: 'read:users:5' if the request route is /users/5).

Example

import { authenticate } from "@labshare/lb-services-auth";
import { Request } from "@loopback/core";

// Attach the decorator at the controller level to require authentication on all methods
// and a scope of `my:shared:scope`
@authenticate({
  scope: 'my:shared:scope'
})
class MyController {
  constructor(
    @inject(RestBindings.Http.REQUEST) public request: Request
  ) {}

  @authenticate()
  @get('/whoAmI', {
    'x-operation-name': 'whoAmI',
    responses: {
      '200': {
        description: '',
        schema: {
          type: 'string',
        },
      },
    },
  })
  async whoAmI(): Promise<string> {
    return 'authenticated data';
  }

  // This route supports both authenticated and anonymous requests
  @authenticate({
    credentialsRequired: false
  })
  @get('/resource', {
    'x-operation-name': 'resource',
    responses: {
      '200': {
        description: '',
        schema: {
          type: 'string',
        },
      },
    },
  })
  async resource(): Promise<string> {
    if (this.request.user) {
      return 'Resource requiring authentication';
    }

    return 'Public resource';
  }

  // This route has an additional Resource Scope requirement. The user's bearer token will need to contain
  // 'read:users' in the `scope` claim. Otherwise, they will receive a 403 in the response.
  @authenticate({
    scope: ['read:users']
  })
  @get('/users', {
    'x-operation-name': 'users',
    responses: {
      '200': {
        description: '',
        schema: {
          type: 'string',
        },
      },
    }
  })
  async users(): Promise<string> {
    return 'users';
  }

  // This route has a dynamic scope parameter for validation.
  // The request will be unauthorized if the JWT does not contain the "tenantId", "someOtherParam" values in the route path and the "someParam" query parameter.
  @authenticate({
    scope: ['{path.tenantId}:read:users:{query.someParam}:{path.someOtherParam}']
  })
  @get('{tenantId}/users')
  async users(
    @param.path.string('tenantId') tenantId: string,
    @param.path.number('someOtherParam') someOtherParam: number,
    @param.query.boolean('someParam') someParam: boolean
  ): Promise<string> {
    return `${tenantId} users';
  }
}

app.controller(MyController);

services-auth's People

Contributors

dkrantsberg avatar greenkeeper[bot] avatar jamilomar avatar kallev avatar keatsk avatar kv979w avatar sat939 avatar semantic-release-bot avatar snyk-bot avatar suhasys avatar

Stargazers

 avatar  avatar

Watchers

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

services-auth's Issues

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository with URL https://[secure]@github.com/LabShare/services-auth.git.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment and make sure the repositoryUrl is configured with a valid Git URL.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

An in-range update of nock is breaking the build 🚨

Version 9.2.6 of nock was just published.

Branch Build failing 🚨
Dependency nock
Current Version 9.2.5
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

nock is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • βœ… continuous-integration/travis-ci/push The Travis CI build passed Details
  • ❌ coverage/coveralls First build on greenkeeper/nock-9.2.6 at 81.013% Details

Release Notes v9.2.6

9.2.6 (2018-05-14)

Bug Fixes

  • match HTTP headers with case insensitivity (#1122) (2676fed)
Commits

The new version differs by 5 commits.

  • 2676fed fix: match HTTP headers with case insensitivity (#1122)
  • 8ce5be8 test: temporary disable test depending on external hosts
  • 5977cdf test: remove airplane mode from '(re-)activate after restore'
  • 704eb25 Follow up on previous test
  • 3111dce test: remove airplane mode from 'allow unmocked option works'

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two-Factor Authentication, make configure the auth-only level is supported. semantic-release cannot publish with the default auth-and-writes level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

The automated release is failing 🚨

🚨 The automated release from the 2x branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the 2x branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://registry.npmjs.org/.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

An in-range update of deprecate is breaking the build 🚨

Version 1.1.0 of deprecate was just published.

Branch Build failing 🚨
Dependency deprecate
Current Version 1.0.0
Type dependency

This version is covered by your current version range and after updating it in your project the build failed.

deprecate is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Commits

The new version differs by 4 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of request is breaking the build 🚨

Version 2.86.0 of request was just published.

Branch Build failing 🚨
Dependency request
Current Version 2.85.0
Type dependency

This version is covered by your current version range and after updating it in your project the build failed.

request is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • βœ… continuous-integration/travis-ci/push The Travis CI build passed Details
  • ❌ coverage/coveralls First build on greenkeeper/request-2.86.0 at 81.013% Details

Commits

The new version differs by 14 commits.

  • 8f2fd4d Update changelog
  • 386c7d8 2.86.0
  • 76a6e5b Merge pull request #2885 from ChALkeR/patch-1
  • db76838 Merge branch 'patch-1' of github.com:ChALkeR/request
  • fb7aeb3 Merge pull request #2942 from simov/fix-tests
  • e47ce95 Add Node v10 build target explicitly
  • 0c5db42 Skip status code 105 on Node > v10
  • d555bd7 Generate server certificates for Node > v10
  • 81f8cb5 Remove redundant code
  • db17497 Use Buffer.from and Buffer.alloc in tests
  • 0d29635 Merge pull request #2923 from gareth-robinson/cifixes
  • 3745cec Correction for Windows OS identification
  • 219a298 Alterations for failing CI tests
  • bbb3a0b 2.85.1

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

The automated release is failing 🚨

🚨 The automated release from the 2x branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the 2x branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://registry.npmjs.org/.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

An in-range update of socket.io-client is breaking the build 🚨

Version 2.1.1 of socket.io-client was just published.

Branch Build failing 🚨
Dependency socket.io-client
Current Version 2.1.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

socket.io-client is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • βœ… continuous-integration/travis-ci/push The Travis CI build passed Details
  • ❌ coverage/coveralls First build on greenkeeper/socket.io-client-2.1.1 at 81.013% Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository with URL https://[secure]@github.com/LabShare/services-auth.git.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment and make sure the repositoryUrl is configured with a valid Git URL.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository with URL https://[secure]@github.com/LabShare/services-auth.git.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment and make sure the repositoryUrl is configured with a valid Git URL.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

An in-range update of @labshare/services is breaking the build 🚨

Version 0.18.514 of @labshare/services was just published.

Branch Build failing 🚨
Dependency @labshare/services
Current Version 0.18.304
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

@labshare/services is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • βœ… continuous-integration/travis-ci/push The Travis CI build passed Details
  • ❌ coverage/coveralls First build on greenkeeper/@labshare/services-0.18.514 at 81.013% Details

Commits

The new version differs by 13 commits.

  • b36123a chore(tests): Improve test coverage SHELL-1508
  • 3175c53 feat(services): Replace custom forced shutdown with NPM's server-shutdown
  • fbe8c29 chore(services): Improve test coverage
  • ae8e7ab chore(Travis): Don't run tests twice
  • 73e486f chore(services): Update test coverage SHELL-1508 #qa/testing
  • 11c636e (chore) Add Coveralls badge
  • 2635aa7 SHELL-1508 #qa/testing Enable Coveralls support
  • b77d1ef Merge pull request #119 from LabShare/greenkeeper/supertest-3.1.0
  • ebbb614 chore(package): update supertest to version 3.1.0
  • 46968f3 Merge pull request #117 from LabShare/greenkeeper/initial
  • 6850889 docs(readme): add Greenkeeper badge
  • 2dff629 chore(package): update dependencies
  • 7aaf985 chore: add Greenkeeper config file

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of supertest is breaking the build 🚨

Version 3.1.0 of supertest was just published.

Branch Build failing 🚨
Dependency supertest
Current Version 3.0.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

supertest is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build failed Details

Release Notes v3.1.0
  • #473 - Remove unused dependency in Readme (thanks @pedro-otero)
  • #472 - Update travis node versions (thanks @rimiti)
  • #470 - Upgrade the superagent node module to resolve security vulnerabilities & fix the proto property deprecation (thanks @levioza)
  • #446 - Fix bug, always pass on errors if no response (thanks @bkeepers)
  • #418 - Add post() examples to the README (thanks @kevinburke)
  • #297 - Add a .host() method to set a host other than 127.0.0.1 (thanks @mikec)
  • #275 - Removed ambiguously misappropriated cultural references from readme (thanks @reallistic)
Commits

The new version differs by 1 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

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.