@icgc-argo/ego-token-utils
Advanced tools
Comparing version 1.0.0 to 2.0.0
@@ -220,3 +220,2 @@ /** | ||
}; | ||
var egoTokenUtils = { | ||
@@ -237,2 +236,3 @@ isPermission: isPermission, | ||
export default egoTokenUtils; | ||
export { isPermission, decodeToken, isValidJwt, isDccMember, isRdpcMember, parseScope, serializeScope, getAuthorizedProgramScopes, canReadProgram, canWriteProgram, isProgramAdmin }; | ||
//# sourceMappingURL=ego-token-utils.es5.js.map |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.egoTokenUtils = factory()); | ||
}(this, (function () { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(factory((global.egoTokenUtils = {}))); | ||
}(this, (function (exports) { 'use strict'; | ||
@@ -226,3 +226,2 @@ /** | ||
}; | ||
var egoTokenUtils = { | ||
@@ -242,5 +241,18 @@ isPermission: isPermission, | ||
return egoTokenUtils; | ||
exports.isPermission = isPermission; | ||
exports.decodeToken = decodeToken; | ||
exports.isValidJwt = isValidJwt; | ||
exports.isDccMember = isDccMember; | ||
exports.isRdpcMember = isRdpcMember; | ||
exports.parseScope = parseScope; | ||
exports.serializeScope = serializeScope; | ||
exports.getAuthorizedProgramScopes = getAuthorizedProgramScopes; | ||
exports.canReadProgram = canReadProgram; | ||
exports.canWriteProgram = canWriteProgram; | ||
exports.isProgramAdmin = isProgramAdmin; | ||
exports.default = egoTokenUtils; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
}))); | ||
//# sourceMappingURL=ego-token-utils.umd.js.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var utils_1 = require("./utils"); | ||
var _jwtDecode = require("jwt-decode"); | ||
var jwtDecode = _jwtDecode; | ||
var PERMISSIONS = { | ||
READ: 'READ', | ||
WRITE: 'WRITE', | ||
ADMIN: 'ADMIN', | ||
DENY: 'DENY' | ||
}; | ||
var DCC_PREFIX = 'program-service.WRITE'; | ||
var RDPC_PREFIX = 'RDPC-'; | ||
var PROGRAM_PREFIX = 'PROGRAM-'; | ||
var PROGRAM_DATA_PREFIX = 'PROGRAMDATA-'; | ||
exports.isPermission = function (str) { | ||
return Object.values(PERMISSIONS).includes(str); | ||
}; | ||
exports.decodeToken = function (egoJwt) { return jwtDecode(egoJwt); }; | ||
exports.isValidJwt = function (egoJwt) { | ||
try { | ||
if (!egoJwt) { | ||
return false; | ||
} | ||
else { | ||
var exp = exports.decodeToken(egoJwt).exp; | ||
if (!(exp * 1000 > Date.now())) { | ||
console.log('expired!!!!'); | ||
} | ||
return exp * 1000 > Date.now(); | ||
} | ||
} | ||
catch (err) { | ||
return false; | ||
} | ||
}; | ||
exports.isDccMember = function (egoJwt) { | ||
try { | ||
var data = exports.decodeToken(egoJwt); | ||
var permissions = data.context.user.permissions; | ||
return permissions.some(function (p) { return p.includes(DCC_PREFIX); }); | ||
} | ||
catch (err) { | ||
return false; | ||
} | ||
}; | ||
exports.isRdpcMember = function (egoJwt) { | ||
try { | ||
var data = exports.decodeToken(egoJwt); | ||
var permissions = data.context.user.permissions; | ||
var rdpcPermissions = permissions.filter(function (p) { | ||
var policy = p.split('.')[0]; | ||
return policy.indexOf(RDPC_PREFIX) === 0; | ||
}); | ||
var isMember = rdpcPermissions.some(function (p) { | ||
return [PERMISSIONS.READ, PERMISSIONS.WRITE, PERMISSIONS.ADMIN].includes(p.split('.')[1]); | ||
}) && !rdpcPermissions.some(function (p) { return [PERMISSIONS.DENY].includes(p.split('.')[1]); }); | ||
return isMember; | ||
} | ||
catch (err) { | ||
return false; | ||
} | ||
}; | ||
exports.parseScope = function (scope) { | ||
var permission = scope.split('.')[1]; | ||
if (exports.isPermission(permission)) { | ||
return { | ||
policy: scope.split('.')[0], | ||
permission: permission | ||
}; | ||
} | ||
else { | ||
throw new Error("invalid scope: " + scope); | ||
} | ||
}; | ||
exports.serializeScope = function (scopeObj) { | ||
if (exports.isPermission(scopeObj.permission)) { | ||
return scopeObj.policy + "." + scopeObj.permission; | ||
} | ||
else { | ||
throw new Error("invalid permission: " + scopeObj.permission); | ||
} | ||
}; | ||
exports.getAuthorizedProgramScopes = function (egoJwt) { | ||
var data = exports.decodeToken(egoJwt); | ||
var permissions = data.context.user.permissions; | ||
var programPermissions = permissions.filter(function (p) { | ||
var policy = p.split('.')[0]; | ||
var output = policy.indexOf(PROGRAM_PREFIX) === 0 && policy.indexOf(PROGRAM_DATA_PREFIX) !== 0; | ||
return output; | ||
}); | ||
return programPermissions.reduce(function (acc, p) { | ||
var scopeObj = exports.parseScope(p); | ||
if ([PERMISSIONS.READ, PERMISSIONS.WRITE, PERMISSIONS.ADMIN].includes(scopeObj.permission) && | ||
![PERMISSIONS.DENY].includes(scopeObj.permission)) { | ||
acc.push(scopeObj); | ||
} | ||
return acc; | ||
}, []); | ||
}; | ||
exports.canReadProgram = function (args) { | ||
var authorizedProgramScopes = exports.getAuthorizedProgramScopes(args.egoJwt); | ||
return authorizedProgramScopes.some(function (_a) { | ||
var policy = _a.policy; | ||
return policy.includes(args.programId); | ||
}); | ||
}; | ||
exports.canWriteProgram = function (args) { | ||
var authorizedProgramScopes = exports.getAuthorizedProgramScopes(args.egoJwt); | ||
return authorizedProgramScopes.some(function (_a) { | ||
var policy = _a.policy, permission = _a.permission; | ||
return policy.includes(args.programId) && [PERMISSIONS.WRITE, PERMISSIONS.ADMIN].includes(permission); | ||
}); | ||
}; | ||
exports.isProgramAdmin = function (args) { | ||
return exports.canWriteProgram(args); | ||
/** TODO: switch to below logic when .ADMIN scope is available */ | ||
// const authorizedProgramScopes = getAuthorizedProgramScopes(args.egoJwt); | ||
// return authorizedProgramScopes.some( | ||
// ({ policy, permission }) => policy.includes(args.programId) && permission === PERMISSIONS.ADMIN, | ||
// ); | ||
}; | ||
exports.default = { | ||
isPermission: utils_1.isPermission, | ||
decodeToken: utils_1.decodeToken, | ||
isValidJwt: utils_1.isValidJwt, | ||
isDccMember: utils_1.isDccMember, | ||
isRdpcMember: utils_1.isRdpcMember, | ||
parseScope: utils_1.parseScope, | ||
serializeScope: utils_1.serializeScope, | ||
getAuthorizedProgramScopes: utils_1.getAuthorizedProgramScopes, | ||
canReadProgram: utils_1.canReadProgram, | ||
canWriteProgram: utils_1.canWriteProgram, | ||
isProgramAdmin: utils_1.isProgramAdmin | ||
isPermission: exports.isPermission, | ||
decodeToken: exports.decodeToken, | ||
isValidJwt: exports.isValidJwt, | ||
isDccMember: exports.isDccMember, | ||
isRdpcMember: exports.isRdpcMember, | ||
parseScope: exports.parseScope, | ||
serializeScope: exports.serializeScope, | ||
getAuthorizedProgramScopes: exports.getAuthorizedProgramScopes, | ||
canReadProgram: exports.canReadProgram, | ||
canWriteProgram: exports.canWriteProgram, | ||
isProgramAdmin: exports.isProgramAdmin | ||
}; | ||
//# sourceMappingURL=ego-token-utils.js.map |
@@ -0,19 +1,64 @@ | ||
declare const PERMISSIONS: { | ||
READ: string; | ||
WRITE: string; | ||
ADMIN: string; | ||
DENY: string; | ||
}; | ||
export declare type EgoJwtData = { | ||
iat: number; | ||
exp: number; | ||
sub: string; | ||
iss: string; | ||
aud: string[]; | ||
jti: string; | ||
context: { | ||
scope: string[]; | ||
user: { | ||
name: string; | ||
email: string; | ||
status: 'APPROVED' | 'DISABLED' | 'PENDING' | 'REJECTED'; | ||
firstName: string; | ||
lastName: string; | ||
createdAt: number; | ||
lastLogin: number; | ||
preferredLanguage: string | undefined; | ||
type: 'ADMIN' | 'USER'; | ||
permissions: string[]; | ||
}; | ||
}; | ||
scope: string[]; | ||
}; | ||
declare type PermissionScopeObj = { | ||
policy: string; | ||
permission: keyof typeof PERMISSIONS; | ||
}; | ||
export declare const isPermission: (str: any) => str is "READ" | "WRITE" | "ADMIN" | "DENY"; | ||
export declare const decodeToken: (egoJwt: string) => EgoJwtData; | ||
export declare const isValidJwt: (egoJwt?: string | undefined) => boolean; | ||
export declare const isDccMember: (egoJwt: string) => boolean; | ||
export declare const isRdpcMember: (egoJwt: string) => boolean; | ||
export declare const parseScope: (scope: string) => PermissionScopeObj; | ||
export declare const serializeScope: (scopeObj: PermissionScopeObj) => string; | ||
export declare const getAuthorizedProgramScopes: (egoJwt: string) => PermissionScopeObj[]; | ||
export declare const canReadProgram: (args: { | ||
egoJwt: string; | ||
programId: string; | ||
}) => boolean; | ||
export declare const canWriteProgram: (args: { | ||
egoJwt: string; | ||
programId: string; | ||
}) => boolean; | ||
export declare const isProgramAdmin: (args: { | ||
egoJwt: string; | ||
programId: string; | ||
}) => boolean; | ||
declare const _default: { | ||
isPermission: (str: any) => str is "READ" | "WRITE" | "ADMIN" | "DENY"; | ||
decodeToken: (egoJwt: string) => import("./utils").EgoJwtData; | ||
decodeToken: (egoJwt: string) => EgoJwtData; | ||
isValidJwt: (egoJwt?: string | undefined) => boolean; | ||
isDccMember: (egoJwt: string) => boolean; | ||
isRdpcMember: (egoJwt: string) => boolean; | ||
parseScope: (scope: string) => { | ||
policy: string; | ||
permission: "READ" | "WRITE" | "ADMIN" | "DENY"; | ||
}; | ||
serializeScope: (scopeObj: { | ||
policy: string; | ||
permission: "READ" | "WRITE" | "ADMIN" | "DENY"; | ||
}) => string; | ||
getAuthorizedProgramScopes: (egoJwt: string) => { | ||
policy: string; | ||
permission: "READ" | "WRITE" | "ADMIN" | "DENY"; | ||
}[]; | ||
parseScope: (scope: string) => PermissionScopeObj; | ||
serializeScope: (scopeObj: PermissionScopeObj) => string; | ||
getAuthorizedProgramScopes: (egoJwt: string) => PermissionScopeObj[]; | ||
canReadProgram: (args: { | ||
@@ -20,0 +65,0 @@ egoJwt: string; |
{ | ||
"name": "@icgc-argo/ego-token-utils", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "", | ||
@@ -15,3 +15,3 @@ "keywords": [], | ||
"type": "git", | ||
"url": "git@github.com:icgc-argo/ego-token-utils.git" | ||
"url": "https://github.com/icgc-argo/ego-token-utils" | ||
}, | ||
@@ -18,0 +18,0 @@ "license": "MIT", |
112
README.md
# Ego Token Utils | ||
[![Coverage Status](https://coveralls.io/repos/github/icgc-argo/ego-token-utils/badge.svg?branch=master)](https://coveralls.io/github/icgc-argo/ego-token-utils?branch=master) | ||
[![Build Status](https://travis-ci.org/icgc-argo/ego-token-utils.svg?branch=master)](https://travis-ci.org/icgc-argo/ego-token-utils) | ||
[![npm version](https://badge.fury.io/js/%40icgc-argo%2Fego-token-utils.svg)](https://badge.fury.io/js/%40icgc-argo%2Fego-token-utils) | ||
[![Prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://prettier.io/) | ||
This project uses the following bootstrap setup: | ||
This repo contains a library of utility functions written in __Typescript__ interpret __Ego JWT__ content in the Argo system. | ||
# [typescript-library-starter](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg) | ||
## Usage | ||
- install: | ||
``` | ||
npm i --save @icgc-argo/ego-token-utils | ||
``` | ||
- use: | ||
```typescript | ||
import TokenUtils from '@icgc-argo/ego-token-utils' | ||
TokenUtils.decodeToken(egoJwt) | ||
TokenUtils.canReadProgram(egoJwt, "PROGRAM-TEST-AU.READ") | ||
... | ||
``` | ||
Interactive documentation is available at: https://icgc-argo.github.io/ego-token-utils/ | ||
A starter project that makes creating a TypeScript library extremely easy. | ||
## Development | ||
This project uses the following bootstrap setup: [typescript-library-starter](https://github.com/alexjoverm/typescript-library-starter) | ||
![](https://i.imgur.com/opUmHp0.png) | ||
### Notes | ||
- `npm i`: install dependencies | ||
- `npm run test:watch`: to start developing with interactive live test | ||
- `npm run build`: to trigger build (for local testing only) | ||
- `npm run commit`: to commit changes. __IMPORTANT__ as commits are analyzed for release | ||
- Once happy, submit a PR to the `develop` branch. | ||
- Releases happen automatically through Travis once merged to `master` | ||
### Usage | ||
```bash | ||
git clone https://github.com/alexjoverm/typescript-library-starter.git YOURFOLDERNAME | ||
cd YOURFOLDERNAME | ||
# Run npm install and write your library name when asked. That's all! | ||
npm install | ||
``` | ||
**Start coding!** `package.json` and entry files are already set up for you, so don't worry about linking to your main file, typings, etc. Just keep those files with the same name. | ||
### Features | ||
- Zero-setup. After running `npm install` things will setup for you :wink: | ||
- **[RollupJS](https://rollupjs.org/)** for multiple optimized bundles following the [standard convention](http://2ality.com/2017/04/setting-up-multi-platform-packages.html) and [Tree-shaking](https://alexjoverm.github.io/2017/03/06/Tree-shaking-with-Webpack-2-TypeScript-and-Babel/) | ||
- Tests, coverage and interactive watch mode using **[Jest](http://facebook.github.io/jest/)** | ||
- **[Prettier](https://github.com/prettier/prettier)** and **[TSLint](https://palantir.github.io/tslint/)** for code formatting and consistency | ||
- **Docs automatic generation and deployment** to `gh-pages`, using **[TypeDoc](http://typedoc.org/)** | ||
- Automatic types `(*.d.ts)` file generation | ||
- **[Travis](https://travis-ci.org)** integration and **[Coveralls](https://coveralls.io/)** report | ||
- (Optional) **Automatic releases and changelog**, using [Semantic release](https://github.com/semantic-release/semantic-release), [Commitizen](https://github.com/commitizen/cz-cli), [Conventional changelog](https://github.com/conventional-changelog/conventional-changelog) and [Husky](https://github.com/typicode/husky) (for the git hooks) | ||
### Importing library | ||
You can import the generated bundle to use the whole library generated by this starter: | ||
```javascript | ||
import myLib from 'mylib' | ||
``` | ||
Additionally, you can import the transpiled modules from `dist/lib` in case you have a modular library: | ||
```javascript | ||
import something from 'mylib/dist/lib/something' | ||
``` | ||
### NPM scripts | ||
- `npm t`: Run test suite | ||
- `npm start`: Run `npm run build` in watch mode | ||
- `npm run test:watch`: Run test suite in [interactive watch mode](http://facebook.github.io/jest/docs/cli.html#watch) | ||
- `npm run test:prod`: Run linting and generate coverage | ||
- `npm run build`: Generate bundles and typings, create docs | ||
- `npm run lint`: Lints code | ||
- `npm run commit`: Commit using conventional commit style ([husky](https://github.com/typicode/husky) will tell you to use it if you haven't :wink:) | ||
### Excluding peerDependencies | ||
On library development, one might want to set some peer dependencies, and thus remove those from the final bundle. You can see in [Rollup docs](https://rollupjs.org/#peer-dependencies) how to do that. | ||
Good news: the setup is here for you, you must only include the dependency name in `external` property within `rollup.config.js`. For example, if you want to exclude `lodash`, just write there `external: ['lodash']`. | ||
#### Setup steps | ||
Follow the console instructions to install semantic release and run it (answer NO to "Do you want a `.travis.yml` file with semantic-release setup?"). | ||
_Note: make sure you've setup `repository.url` in your `package.json` file_ | ||
```bash | ||
npm install -g semantic-release-cli | ||
semantic-release-cli setup | ||
# IMPORTANT!! Answer NO to "Do you want a `.travis.yml` file with semantic-release setup?" question. It is already prepared for you :P | ||
``` | ||
From now on, you'll need to use `npm run commit`, which is a convenient way to create conventional commits. | ||
Automatic releases are possible thanks to [semantic release](https://github.com/semantic-release/semantic-release), which publishes your code automatically on [github](https://github.com/) and [npm](https://www.npmjs.com/), plus generates automatically a changelog. This setup is highly influenced by [Kent C. Dodds course on egghead.io](https://egghead.io/courses/how-to-write-an-open-source-javascript-library) | ||
### Git Hooks | ||
There is already set a `precommit` hook for formatting your code with Prettier :nail_care: | ||
By default, there are two disabled git hooks. They're set up when you run the `npm run semantic-release-prepare` script. They make sure: | ||
- You follow a [conventional commit message](https://github.com/conventional-changelog/conventional-changelog) | ||
- Your build is not going to fail in [Travis](https://travis-ci.org) (or your CI server), since it's runned locally before `git push` | ||
This makes more sense in combination with [automatic releases](#automatic-releases) | ||
Further development notes can be found [here](/DEVELOPMENT.md) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96432
10
666
36