Skip to content
This repository has been archived by the owner on Aug 2, 2020. It is now read-only.

Commit

Permalink
Refactores SDK Init to Object
Browse files Browse the repository at this point in the history
- Introduced interface SDKConfig.
- Refactored SDK init method to accept SDKConfig as only param.
- Refactored SDK methods to access SDK config via private config attribute.
- Updated README.
- Bumped version to v5.8.2.
  • Loading branch information
mahmoudajawad committed Nov 6, 2019
1 parent beec6c7 commit fbd0c15
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 45 deletions.
31 changes: 19 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ npm i --save ng-limp

## How to Use
1. Import `NgLimpModule` in your module imports.
2. Initiate the API, in your component, using:
2. Initiate the SDK, in your component, using:
```typescript
import { Component, OnInit } from '@angular/core';

Expand All @@ -30,20 +30,23 @@ export class AppComponent implements OnInit {
constructor(private api: ApiService) {}

ngOnInit() {
this.api.authAttrs = ['email'];
this.api.init('ws://localhost:8081/ws', '__ANON');
this.api.init({
api: 'ws://localhost:8081/ws',
anonToken: '__ANON',
authAttrs: ['email']
});
}
}
```

## Setting Global Attributes
There are three attributes that you can optionally set before initiating the SDK:
1. `debug`: A `Boolean` representing the debug mode status on the SDK. If `true`, you would see verbose messages in the browser console about messages transferred are received. Default `false`.
2. `fileChunkSize`: A `Number` representing the chunk size in bytes of the files being uploaded as part of the process of pushing binary data to LIMP app. Default `512000`.
3. `authHashLevel`: Either `5.0` or `5.6`. With the change to auth hash generation introduced in APIv5.6 of LIMP, some legacy apps are left without the ability to upgrade to APIv5.6 and beyond due to hashes difference. SDKv5.7 is adding `authHashLevel` to allow developers to use higher APIs and SDKs with legacy apps. Default `5.6`;

Another attribute which is mandatory for first time initialisation of the SDK:
4. `authAttrs`: As of LIMP APIv5.8, LIMP apps don't have strict User module attrs structure. This includes the authentication attrs that are set per app. This attribute represents an `Array<string>` referring to the same authentication attrs of the app.
## SDK Config
When initialising the SDK, you should pass an object matching the interface `SDKConfig`, which has the following attributes:
1. `api` (Required): The URI of LIMP app you are connecting to.
2. `anonToken` (Required): LIMP app `ANON_TOKEN`.
3. `authAttrs` (Required): As of LIMP APIv5.8, LIMP apps don't have strict User module attrs structure. This includes the authentication attrs that are set per app. This attribute represents an `Array<string>` referring to the same authentication attrs of the app.
4. `debug` (Optional): A `Boolean` representing the debug mode status on the SDK. If `true`, you would see verbose messages in the browser console about messages transferred are received. Default `false`.
5. `fileChunkSize` (Optional): A `Number` representing the chunk size in bytes of the files being uploaded as part of the process of pushing binary data to LIMP app. Default `512000`.
6. `authHashLevel` (Optional): Either `5.0` or `5.6`. With the change to auth hash generation introduced in APIv5.6 of LIMP, some legacy apps are left without the ability to upgrade to APIv5.6 and beyond due to hashes difference. SDKv5.7 is adding `authHashLevel` to allow developers to use higher APIs and SDKs with legacy apps. Default `5.6`;

# Best Practices
You can use the SDK 100% per your style of development, however we have some tips:
Expand Down Expand Up @@ -112,7 +115,11 @@ export class AppComponent implements OnInit {
}

init(): void {
this.api.init('ws://localhost:8081/ws', 'http://localhost:8081', '__ANON');
this.api.init({
api: 'ws://localhost:8081/ws',
anonToken: '__ANON',
authAttrs: ['email']
});
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ng-limp",
"version": "5.8.1",
"version": "5.8.2",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down
11 changes: 8 additions & 3 deletions projects/ng-limp-test/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class AppComponent implements OnInit {
constructor(public api: ApiService) { }

ngOnInit() {
this.api.debug = true;
this.api.authAttrs = ['email'];
// this.api.debug = true;
// this.api.authAttrs = ['email'];
this.api.inited$.subscribe((init) => {
if (init) {
try {
Expand Down Expand Up @@ -49,7 +49,12 @@ export class AppComponent implements OnInit {
}

init(): void {
this.api.init('ws://localhost:8081/ws', '__ANON_TOKEN_f00000000000000000000012');
this.api.init({
api: 'ws://localhost:8081/ws',
anonToken: '__ANON_TOKEN_f00000000000000000000012',
authAttrs: ['email'],
debug: true
});
}

auth(): void {
Expand Down
2 changes: 1 addition & 1 deletion projects/ng-limp/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ng-limp",
"description": "Angular SDK for LIMP",
"version": "5.8.1",
"version": "5.8.2",
"license": "SEE LICENSE IN LICENSE",
"author": {
"name": "Mahmoud Abduljawad",
Expand Down
9 changes: 9 additions & 0 deletions projects/ng-limp/src/lib/ng-limp.models.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
export interface SDKConfig {
api: string;
anonToken: string;
authAttrs: Array<string>;
debug?: boolean;
fileChunkSize?: number;
authHashLevel?: 5.0 | 5.6;
}

export interface QueryStep {
$search?: string;
$sort?: {
Expand Down
58 changes: 30 additions & 28 deletions projects/ng-limp/src/lib/ng-limp.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ import { webSocket } from 'rxjs/webSocket';

import * as rs from 'jsrsasign';

import { callArgs, Res, Doc, Session } from './ng-limp.models';
import { SDKConfig, callArgs, Res, Doc, Session } from './ng-limp.models';
import { CacheService } from './cache.service';

const JWS = rs.jws.JWS;

@Injectable()
export class ApiService {

debug: boolean = false;
fileChunkSize: number = 500 * 1024;
authHashLevel: 5.0 | 5.6 = 5.6;
authAttrs: Array<string> = [];
private config: SDKConfig = {
api: null,
anonToken: null,
authAttrs: [],
debug: false,
fileChunkSize: 500 * 1024,
authHashLevel: 5.6
}


private subject!: Subject<any>;
private conn: Subject<Res<Doc>> = new Subject();
Expand All @@ -32,9 +37,6 @@ export class ApiService {
auth: new Array()
};

private api: string;
private anonToken!: string;

inited: boolean;
inited$: Subject<boolean> = new Subject();

Expand Down Expand Up @@ -65,8 +67,8 @@ export class ApiService {
let tEnd = Math.round((new Date() as any) / 1000) + 86400;
let sHeader = JSON.stringify(oHeader);
let sPayload = JSON.stringify({ ...call.callArgs, iat: tNow, exp: tEnd });
let sJWT = JWS.sign('HS256', sHeader, sPayload, { utf8: this.anonToken });
this.log('info', 'sending noAuth queue request as JWT token:', call.callArgs, this.anonToken);
let sJWT = JWS.sign('HS256', sHeader, sPayload, { utf8: this.config.anonToken });
this.log('info', 'sending noAuth queue request as JWT token:', call.callArgs, this.config.anonToken);
this.subject.next({ token: sJWT, call_id: call.callArgs.call_id });
}
});
Expand Down Expand Up @@ -95,7 +97,7 @@ export class ApiService {
let sHeader = JSON.stringify(oHeader);
let sPayload = JSON.stringify({ ...call.callArgs, iat: tNow, exp: tEnd });
let sJWT = JWS.sign('HS256', sHeader, sPayload, { utf8: this.session.token });
this.log('info', 'sending auth queue request as JWT token:', call.callArgs, this.anonToken);
this.log('info', 'sending auth queue request as JWT token:', call.callArgs, this.config.anonToken);
this.subject.next({ token: sJWT, call_id: call.callArgs.call_id });
}
});
Expand All @@ -107,18 +109,18 @@ export class ApiService {
}

log(level: 'log' | 'info' | 'warn' | 'error', ...data: Array<any>): void {
if (!this.debug) return;
if (!this.config.debug) return;
console[level](...data);
}

init(api: string, anonToken: string): Observable<Res<Doc>> {
if (this.authAttrs.length == 0) {
init(config: SDKConfig): Observable<Res<Doc>> {
Object.assign(this.config, config);
if (this.config.authAttrs.length == 0) {
throw new Error('SDK authAttrs not set')
}
this.log('log', 'Resetting SDK before init');
this.reset();
this.api = api;
this.subject = webSocket(this.api);
this.subject = webSocket(this.config.api);

this.log('log', 'Attempting to connect');

Expand All @@ -128,7 +130,7 @@ export class ApiService {
this.conn.next(res);
if (res.args && res.args.code == 'CORE_CONN_READY') {
this.reset();
this.anonToken = anonToken;
this.config.anonToken = config.anonToken;
this.call('conn/verify', {}).subscribe();
} else if (res.args && res.args.code == 'CORE_CONN_OK') {
this.inited = true;
Expand Down Expand Up @@ -192,7 +194,7 @@ export class ApiService {
call(endpoint: string, callArgs: callArgs, awaitAuth: boolean = false): Observable<Res<Doc>> {

callArgs.sid = (this.authed) ? callArgs.sid || this.cache.get('sid') || 'f00000000000000000000012' : callArgs.sid || 'f00000000000000000000012';
callArgs.token = (this.authed) ? callArgs.token || this.cache.get('token') || this.anonToken : callArgs.token || this.anonToken;
callArgs.token = (this.authed) ? callArgs.token || this.cache.get('token') || this.config.anonToken : callArgs.token || this.config.anonToken;
callArgs.query = callArgs.query || [];
callArgs.doc = callArgs.doc || {};

Expand Down Expand Up @@ -237,18 +239,18 @@ export class ApiService {
attr: attr,
index: i,
chunk: chunkIndex,
total: Math.ceil(byteArray.length / this.fileChunkSize),
total: Math.ceil(byteArray.length / this.config.fileChunkSize),
file: {
name: files[attr][i].name,
size: files[attr][i].size,
type: files[attr][i].type,
lastModified: files[attr][i].lastModified,
content: byteArray.slice(byteArrayIndex, byteArrayIndex + this.fileChunkSize).join(',')
content: byteArray.slice(byteArrayIndex, byteArrayIndex + this.config.fileChunkSize).join(',')
}
}}, awaitAuth);
fileUploads.push(fileUpload);

byteArrayIndex += this.fileChunkSize;
byteArrayIndex += this.config.fileChunkSize;
chunkIndex += 1;
}
observer.complete();
Expand Down Expand Up @@ -355,23 +357,23 @@ export class ApiService {
}

generateAuthHash(authVar: string, authVal: string, password: string): string {
if (this.authAttrs.indexOf(authVar) == -1) {
throw new Error(`Unkown authVar '${authVar}'. Accepted authAttrs: '${this.authAttrs.join(', ')}'`)
if (this.config.authAttrs.indexOf(authVar) == -1) {
throw new Error(`Unkown authVar '${authVar}'. Accepted authAttrs: '${this.config.authAttrs.join(', ')}'`)
}
let oHeader = { alg: 'HS256', typ: 'JWT' };
let sHeader = JSON.stringify(oHeader);
let hashObj = [authVar, authVal, password];
if (this.authHashLevel == 5.6) {
hashObj.push(this.anonToken);
if (this.config.authHashLevel == 5.6) {
hashObj.push(this.config.anonToken);
}
let sPayload = JSON.stringify({ hash: hashObj });
let sJWT = JWS.sign('HS256', sHeader, sPayload, { utf8: password });
return sJWT.split('.')[1];
}

auth(authVar: string, authVal: string, password: string): Observable<Res<Doc>> {
if (this.authAttrs.indexOf(authVar) == -1) {
throw new Error(`Unkown authVar '${authVar}'. Accepted authAttrs: '${this.authAttrs.join(', ')}'`)
if (this.config.authAttrs.indexOf(authVar) == -1) {
throw new Error(`Unkown authVar '${authVar}'. Accepted authAttrs: '${this.config.authAttrs.join(', ')}'`)
}
let doc: any = { hash: this.generateAuthHash(authVar, authVal, password) };
doc[authVar] = authVal;
Expand All @@ -389,7 +391,7 @@ export class ApiService {
let sJWT = JWS.sign('HS256', sHeader, sPayload, { utf8: token });
let call: Observable<Res<Doc>> = this.call('session/reauth', {
sid: 'f00000000000000000000012',
token: this.anonToken,
token: this.config.anonToken,
query: [
{ _id: sid || 'f00000000000000000000012', hash: sJWT.split('.')[1] }
]
Expand Down

0 comments on commit fbd0c15

Please sign in to comment.