@chevre/domain
Version:
Chevre Domain Library for Node.js
164 lines (163 loc) • 8.06 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PassportRepo = void 0;
const createDebug = require("debug");
const jwt = require("jsonwebtoken");
const moment = require("moment");
const factory = require("../factory");
const concurrentLock_1 = require("./concurrentLock");
const debug = createDebug('chevre-domain:repo:passport');
/**
* 取引許可証リポジトリ
*/
class PassportRepo {
constructor(redisClient, options) {
this.concurrentLockRepo = new concurrentLock_1.ConcurrentLockRepo({ redisClient });
// this.redisClient = redisClient;
this.options = options;
}
static CREATE_VERIFIED_PASSPORT(params) {
var _a;
if (typeof params === 'string' || params === undefined) {
throw new factory.errors.Argument('decoded must be an object');
}
if (typeof params.scope !== 'string' || params.scope === '') {
throw new factory.errors.ArgumentNull('scope');
}
if (typeof params.iat !== 'number') {
throw new factory.errors.Argument('iat', 'iat must be number');
}
if (typeof params.exp !== 'number') {
throw new factory.errors.Argument('exp', 'exp must be number');
}
if (typeof params.iss !== 'string' || params.iss === '') {
throw new factory.errors.ArgumentNull('iss');
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (typeof ((_a = params.issueUnit) === null || _a === void 0 ? void 0 : _a.identifier) !== 'string' || params.issueUnit.identifier === '') {
throw new factory.errors.Argument('issueUnit.identifier', 'issueUnit.identifier must be string');
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (typeof params.issueUnit.numberOfRequests !== 'number') {
throw new factory.errors.Argument('issueUnit.numberOfRequests', 'issueUnit.numberOfRequests must be number');
}
const identifier = `${params.issueUnit.identifier}:${params.issueUnit.numberOfRequests}`;
return Object.assign({ identifier, scope: params.scope, iat: params.iat, exp: params.exp, iss: params.iss,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
project: params.project,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
issueUnit: params.issueUnit }, (Array.isArray(params.aud)) ? { aud: params.aud } : undefined);
}
static CREATE_REDIS_KEY(params) {
return `chvr:lockPassport:${params.identifier}`;
}
lock(params) {
return __awaiter(this, void 0, void 0, function* () {
const now = moment();
const passportExpires = moment.unix(params.exp);
const key = PassportRepo.CREATE_REDIS_KEY(params);
const expires = (passportExpires.isAfter(now))
? passportExpires.toDate()
: now.add(1, 'second')
.toDate();
// reimplement using concurrentLockRepo(2025-05-27~)
try {
yield this.concurrentLockRepo.lock({
project: { id: params.project.id, typeOf: factory.organizationType.Project },
about: { identifier: key, typeOf: 'Thing' },
expires,
audience: { identifier: '1', typeOf: 'Audience' }
});
debug('locked,', params.issueUnit.identifier, passportExpires);
}
catch (error) {
throw new factory.errors.AlreadyInUse('passport', [], 'passport already in use');
}
// const ttl = (passportExpires.isAfter(now))
// ? moment.unix(params.exp)
// .diff(moment(), 'seconds')
// : 1;
// const results = await this.redisClient.multi()
// .setNX(key, '1')
// .expire(key, ttl)
// .exec();
// debug('locked,', params.issueUnit.identifier, now, passportExpires, ttl, results);
// if (Array.isArray(results) && (results[0] === 1 || (<any>results)[0] === true)) {
// return;
// } else {
// throw new factory.errors.AlreadyInUse('passport', [], 'passport already in use');
// }
});
}
/**
* 許可証トークンがあれば検証する
*/
validatePassportTokenIfExist(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
let passport;
let customerType;
if (typeof ((_b = (_a = params.object) === null || _a === void 0 ? void 0 : _a.passport) === null || _b === void 0 ? void 0 : _b.token) === 'string') {
try {
passport = yield this.verify({
token: params.object.passport.token
// secret: this.options.secret
});
}
catch (error) {
let message = `Invalid token: ${error.message}`;
if (error instanceof jwt.JsonWebTokenError) {
// remove -> 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
const indexOfExpected = message.indexOf('expected:');
if (indexOfExpected >= 0) {
message = message.substring(0, indexOfExpected);
}
}
throw new factory.errors.Argument('passport.token', message);
}
// 許可証バリデーション
if (typeof this.options.passportValidator === 'function') {
if (!this.options.passportValidator({ passport })) {
throw new factory.errors.Argument('passport.token', 'passportValidator requirement not satisfied');
}
}
// カスタマータイプ決定(2023-11-20~)
// スコープのフォーマットは、Transaction:${TransactionType}:${sellerId}:${customerType}
const splittedScope = passport.scope.split(':');
// tslint:disable-next-line:no-magic-numbers
customerType = splittedScope[3];
}
return Object.assign(Object.assign({}, (typeof customerType === 'string') ? { customerType } : undefined), (passport !== undefined) ? { passport } : undefined);
});
}
/**
* 暗号化された許可証を検証する
*/
verify(params) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
jwt.verify(params.token, this.options.secret, {
algorithms: ['HS256'],
issuer: this.options.issuers // add verify issuer(2024-07-08~)
}, (err, decoded) => {
if (err instanceof Error) {
reject(err);
}
else {
resolve(PassportRepo.CREATE_VERIFIED_PASSPORT(decoded));
}
});
});
});
}
}
exports.PassportRepo = PassportRepo;
;