stackpress
Version:
Incept is a content management framework.
116 lines (115 loc) • 3.35 kB
JavaScript
import jwt from 'jsonwebtoken';
import Exception from '../Exception';
import { matchAnyEvent, matchAnyRoute } from './helpers';
export default class SessionServer {
static _access = {};
static _expires = 0;
static _key = 'session';
static _seed = 'abc123';
static get access() {
return this._access;
}
static get seed() {
return this._seed;
}
static get key() {
return this._key;
}
static set expires(value) {
this._expires = value;
}
static configure(key, seed, access) {
this._key = key;
this._seed = seed;
this._access = access;
return this;
}
static authorize(req, res, permits = []) {
const session = this.load(req);
permits.unshift({
method: req.method.toUpperCase(),
route: req.url.pathname
});
if (!session.can(...permits)) {
res.setError(Exception
.for('Unauthorized')
.withCode(401)
.toResponse());
return false;
}
res.setResults(session.authorization);
return true;
}
static create(data) {
if (!this._expires) {
return jwt.sign(data, this.seed);
}
return jwt.sign(data, this.seed, {
expiresIn: this._expires
});
}
static token(req) {
if (req.session.has(this.key)) {
return req.session(this.key);
}
return null;
}
static load(token) {
if (typeof token === 'string') {
return new SessionServer(token);
}
return new SessionServer(this.token(token) || '');
}
token;
_data;
get authorization() {
return {
id: 0,
roles: ['GUEST'],
...(this.data || {}),
token: this.token,
permits: this.permits()
};
}
get data() {
if (typeof this._data === 'undefined') {
this._data = null;
if (this.token.length) {
try {
const response = jwt.verify(this.token, SessionServer.seed);
this._data = typeof response === 'string'
? JSON.parse(response)
: response;
}
catch (e) { }
}
}
return this._data;
}
get guest() {
return this.data === null;
}
constructor(token) {
this.token = token;
}
can(...permits) {
if (permits.length === 0) {
return true;
}
const permissions = this.permits();
const events = permissions.filter(permission => typeof permission === 'string');
const routes = permissions.filter(permission => typeof permission !== 'string');
return Array.isArray(permits) && permits.every(permit => typeof permit === 'string'
? matchAnyEvent(permit, events)
: matchAnyRoute(permit, routes));
}
permits() {
const roles = this.data?.roles || ['GUEST'];
return roles.map(role => SessionServer.access[role] || []).flat().filter((value, index, self) => self.indexOf(value) === index);
}
save(res) {
res.session.set(SessionServer.key, this.token);
return this;
}
}
;