Skip to content
This repository was archived by the owner on Aug 22, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ lib
*.DS_Store
config
yarn.lock
yarn-error.log
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint import/prefer-default-export: 0 */
export const GRANT_TYPE_PASSWORD = "password";
export const GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
12 changes: 12 additions & 0 deletions src/model/descriptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,21 @@ const descriptor = {
access_token: {
type: "string",
},
access_created: {
type: "#DateTime",
},
expires_in: {
type: "integer",
},
refresh_token: {
type: "string",
},
refresh_expires_in: {
type: "integer",
},
refresh_created: {
type: "#DateTime",
},
scope: {
type: "array",
arraytype: "string",
Expand Down
142 changes: 117 additions & 25 deletions src/model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
import { StringTools, dbCreate } from "zoapp-core";
import descriptor from "./descriptor";
import { GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN } from "../constants";

export class ZOAuthModel {
constructor(config = {}, database = null) {
Expand All @@ -17,6 +18,7 @@ export class ZOAuthModel {
}
this.config = config;
this.tokenExpiration = this.config.tokenExpiration || 3600;
this.refreshTokenExpiration = this.config.refreshTokenExpiration || 86400;
}

async open() {
Expand All @@ -43,6 +45,10 @@ export class ZOAuthModel {
return this.database.generateToken(48);
}

generateRefreshToken() {
return this.database.generateToken(32);
}

generateId() {
return this.database.generateToken(32);
}
Expand Down Expand Up @@ -300,55 +306,141 @@ export class ZOAuthModel {
}

async getAccessToken(
grantType,
refreshToken,
clientId,
userId,
scope,
expiration = this.tokenExpiration,
sessions = this.getSessions(),
) {
let accessToken = null;
if (clientId && userId) {
const time = Date.now();
let id = `${clientId}-${userId}`;
accessToken = await sessions.getItem(id);
if (!accessToken) {
accessToken = {
access_token: this.generateAccessToken(),
expires_in: expiration,
scope,
client_id: clientId,
user_id: userId,
id,
created: time,
};
id = null;
let actualSession = null;
const time = Date.now();
if (grantType === GRANT_TYPE_PASSWORD) {
if (clientId && userId) {
let id = `${clientId}-${userId}`;
actualSession = await sessions.getItem(id);
if (!actualSession) {
const newRefreshToken = await this.getRefreshToken();
actualSession = await this.createSession(id, scope, {
expiration,
clientId,
userId,
newRefreshToken,
time,
});
id = null;
} else {
actualSession.last = time;
// TODO handle token expiration
if (scope) {
actualSession.scope = scope;
}
}
await sessions.setItem(id, actualSession);
} else {
accessToken.last = time;
// TODO handle token expiration
if (scope) {
accessToken.scope = scope;
actualSession = { error: "Require credentials" };
}
} else if (grantType === GRANT_TYPE_REFRESH_TOKEN) {
if (refreshToken) {
actualSession = await sessions.getItem(`refresh_token=${refreshToken}`);
if (actualSession !== null) {
const sessionId = actualSession.id;
const newRefreshToken = await this.getRefreshToken();
actualSession = await this.refreshSession({
expiration,
newRefreshToken,
time,
});
await sessions.setItem(sessionId, actualSession);
} else {
actualSession = { error: "Wrong refresh_token" };
}
} else {
actualSession = { error: "Require refresh_token" };
}
await sessions.setItem(id, accessToken);
// this.database.flush();
} else {
actualSession = { error: "Request Failed, unknown grant_type" };
}
return accessToken;
return actualSession;
}

async createSession(id, scope, params) {
let session = {};
session = {
access_token: this.generateAccessToken(),
expires_in: params.expiration,
scope,
client_id: params.clientId,
user_id: params.userId,
id,
access_created: params.time,
created: params.time,
refresh_token: params.newRefreshToken.refresh_token,
refresh_expires_in: params.newRefreshToken.refresh_expires_in,
refresh_created: params.newRefreshToken.refresh_created,
};
return session;
}

async refreshSession(param) {
let session = {};
session = {
access_token: this.generateAccessToken(),
expires_in: param.expiration,
access_created: param.time,
refresh_token: param.newRefreshToken.refresh_token,
refresh_expires_in: param.newRefreshToken.refresh_expires_in,
refresh_created: param.newRefreshToken.refresh_created,
};
return session;
}

async getRefreshToken(expiration = this.refreshTokenExpiration) {
const time = Date.now();
const refreshToken = {
refresh_token: this.generateRefreshToken(),
refresh_expires_in: expiration,
refresh_created: time,
};
return refreshToken;
}

async validateAccessToken(accessToken, sessions = this.getSessions()) {
let access = null;
if (accessToken) {
await sessions.nextItem((a) => {
if (a.access_token === accessToken) {
access = a;
return true;
const expireTime = a.expires_in * 1000;
const expirationDate = a.access_created + expireTime;
if (expirationDate > new Date().getTime()) {
access = a;
return true;
}
}
return false;
});
}
return access;
}

async validateRefreshToken(refreshToken, sessions = this.getSessions()) {
let refresh = null;
if (refreshToken) {
await sessions.nextItem((a) => {
if (a.refresh_token === refreshToken) {
const expirationDate = a.created + a.refresh_expires_in * 1000;
if (expirationDate > new Date().getTime()) {
refresh = a;
return true;
}
}
return false;
});
}
return refresh;
}

/* eslint-disable no-unused-vars */
/* eslint-disable class-methods-use-this */
validateScope(scope) {
Expand Down
Loading