@adonisjs/auth
Version:
Official authentication provider for Adonis framework
130 lines (129 loc) • 4.08 kB
JavaScript
;
/*
* @adonisjs/auth
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenRedisProvider = void 0;
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("@poppinss/utils/build/helpers");
const ProviderToken_1 = require("../../Tokens/ProviderToken");
/**
* Redis backed tokens provider.
*/
class TokenRedisProvider {
constructor(config, redis) {
this.config = config;
this.redis = redis;
/**
* The foreign key column
*/
this.foreignKey = this.config.foreignKey || 'user_id';
}
/**
* Returns the singleton instance of the redis connection
*/
getRedisConnection() {
/**
* Use custom connection if defined
*/
if (this.connection) {
return typeof this.connection === 'string'
? this.redis.connection(this.connection)
: this.connection;
}
/**
* Config must have a connection defined
*/
if (!this.config.redisConnection) {
throw new utils_1.Exception('Missing "redisConnection" property for auth redis provider inside "config/auth" file', 500, 'E_INVALID_AUTH_REDIS_CONFIG');
}
return this.redis.connection(this.config.redisConnection);
}
/**
* Parse the stringified redis token value to an object
*/
parseToken(token) {
if (!token) {
return null;
}
try {
const tokenRow = JSON.parse(token);
if (!tokenRow.token || !tokenRow.name || !tokenRow[this.foreignKey]) {
return null;
}
return tokenRow;
}
catch {
return null;
}
}
/**
* Define custom connection
*/
setConnection(connection) {
this.connection = connection;
return this;
}
/**
* Reads the token using the lookup token id
*/
async read(tokenId, tokenHash, tokenType) {
/**
* Find token using id
*/
const tokenRow = this.parseToken(await this.getRedisConnection().get(`${tokenType}:${tokenId}`));
if (!tokenRow) {
return null;
}
/**
* Ensure hash of the user provided value is same as the one inside
* the database
*/
if (!(0, helpers_1.safeEqual)(tokenRow.token, tokenHash)) {
return null;
}
const { name, [this.foreignKey]: userId, token: value, ...meta } = tokenRow;
const token = new ProviderToken_1.ProviderToken(name, value, userId, tokenType);
token.meta = meta;
return token;
}
/**
* Saves the token and returns the persisted token lookup id, which
* is a cuid.
*/
async write(token) {
/**
* Payload to save to the database
*/
const payload = {
[this.foreignKey]: token.userId,
name: token.name,
token: token.tokenHash,
...token.meta,
};
const ttl = token.expiresAt ? Math.ceil(token.expiresAt.diffNow('seconds').seconds) : 0;
const tokenId = (0, helpers_1.cuid)();
if (token.expiresAt && ttl <= 0) {
throw new utils_1.Exception('The expiry date/time should be in the future', 500, 'E_INVALID_TOKEN_EXPIRY');
}
if (token.expiresAt) {
await this.getRedisConnection().setex(`${token.type}:${tokenId}`, ttl, JSON.stringify(payload));
}
else {
await this.getRedisConnection().set(`${token.type}:${tokenId}`, JSON.stringify(payload));
}
return tokenId;
}
/**
* Removes a given token
*/
async destroy(tokenId, tokenType) {
await this.getRedisConnection().del(`${tokenType}:${tokenId}`);
}
}
exports.TokenRedisProvider = TokenRedisProvider;