|
|
@@ -1,7 +1,9 @@
|
|
|
import crypto from 'crypto';
|
|
|
|
|
|
import type { Ref, IUserHasId } from '@growi/core/dist/interfaces';
|
|
|
-import type { Document, Model, Types } from 'mongoose';
|
|
|
+import type {
|
|
|
+ Document, Model, Types, HydratedDocument,
|
|
|
+} from 'mongoose';
|
|
|
import { Schema } from 'mongoose';
|
|
|
import mongoosePaginate from 'mongoose-paginate-v2';
|
|
|
import uniqueValidator from 'mongoose-unique-validator';
|
|
|
@@ -14,6 +16,14 @@ const logger = loggerFactory('growi:models:access-token');
|
|
|
|
|
|
const generateTokenHash = (token: string) => crypto.createHash('sha256').update(token).digest('hex');
|
|
|
|
|
|
+type GenerateTokenResult = {
|
|
|
+ token: string,
|
|
|
+ _id: Types.ObjectId,
|
|
|
+ expiredAt: Date,
|
|
|
+ scope?: string[],
|
|
|
+ description?: string,
|
|
|
+}
|
|
|
+
|
|
|
export type IAccessToken = {
|
|
|
user: Ref<IUserHasId>,
|
|
|
tokenHash: string,
|
|
|
@@ -27,13 +37,13 @@ export interface IAccessTokenDocument extends IAccessToken, Document {
|
|
|
}
|
|
|
|
|
|
export interface IAccessTokenModel extends Model<IAccessTokenDocument> {
|
|
|
- generateToken: (userId: Types.ObjectId, expiredAt: Date, scope: string[], description?: string,) => Promise<string>
|
|
|
+ generateToken: (userId: Types.ObjectId | string, expiredAt: Date, scope?: string[], description?: string,) => Promise<GenerateTokenResult>
|
|
|
deleteToken: (token: string) => Promise<void>
|
|
|
- deleteTokenById: (tokenId: Types.ObjectId) => Promise<void>
|
|
|
- deleteAllTokensByUserId: (userId: Types.ObjectId) => Promise<void>
|
|
|
+ deleteTokenById: (tokenId: Types.ObjectId | string) => Promise<void>
|
|
|
+ deleteAllTokensByUserId: (userId: Types.ObjectId | string) => Promise<void>
|
|
|
deleteExpiredToken: () => Promise<void>
|
|
|
- findUserIdByToken: (token: string) => Promise<Types.ObjectId>
|
|
|
- findTokenByUserId: (userId: Types.ObjectId) => Promise<IAccessTokenDocument[]>
|
|
|
+ findUserIdByToken: (token: string) => Promise<HydratedDocument<IAccessTokenDocument> | null>
|
|
|
+ findTokenByUserId: (userId: Types.ObjectId | string) => Promise<HydratedDocument<IAccessTokenDocument>[] | null>
|
|
|
validateTokenScopes: (token: string, requiredScope: string[]) => Promise<boolean>
|
|
|
}
|
|
|
|
|
|
@@ -50,7 +60,7 @@ const accessTokenSchema = new Schema<IAccessTokenDocument, IAccessTokenModel>({
|
|
|
accessTokenSchema.plugin(mongoosePaginate);
|
|
|
accessTokenSchema.plugin(uniqueValidator);
|
|
|
|
|
|
-accessTokenSchema.statics.generateToken = async function(userId: Types.ObjectId, expiredAt: Date, scope?: string[], description?: string) {
|
|
|
+accessTokenSchema.statics.generateToken = async function(userId: Types.ObjectId | string, expiredAt: Date, scope?: string[], description?: string) {
|
|
|
|
|
|
const token = crypto.randomBytes(32).toString('hex');
|
|
|
const tokenHash = generateTokenHash(token);
|
|
|
@@ -73,20 +83,20 @@ accessTokenSchema.statics.generateToken = async function(userId: Types.ObjectId,
|
|
|
|
|
|
accessTokenSchema.statics.deleteToken = async function(token: string) {
|
|
|
const tokenHash = generateTokenHash(token);
|
|
|
- return this.deleteOne({ tokenHash });
|
|
|
+ await this.deleteOne({ tokenHash });
|
|
|
};
|
|
|
|
|
|
-accessTokenSchema.statics.deleteTokenById = async function(tokenId: Types.ObjectId) {
|
|
|
- return this.deleteOne({ _id: tokenId });
|
|
|
+accessTokenSchema.statics.deleteTokenById = async function(tokenId: Types.ObjectId | string) {
|
|
|
+ await this.deleteOne({ _id: tokenId });
|
|
|
};
|
|
|
|
|
|
-accessTokenSchema.statics.deleteAllTokensByUserId = async function(userId: Types.ObjectId) {
|
|
|
- return this.deleteMany({ user: userId });
|
|
|
+accessTokenSchema.statics.deleteAllTokensByUserId = async function(userId: Types.ObjectId | string) {
|
|
|
+ await this.deleteMany({ user: userId });
|
|
|
};
|
|
|
|
|
|
accessTokenSchema.statics.deleteExpiredToken = async function() {
|
|
|
const now = new Date();
|
|
|
- return this.deleteMany({ expiredAt: { $lte: now } });
|
|
|
+ await this.deleteMany({ expiredAt: { $lte: now } });
|
|
|
};
|
|
|
|
|
|
accessTokenSchema.statics.findUserIdByToken = async function(token: string) {
|
|
|
@@ -95,7 +105,7 @@ accessTokenSchema.statics.findUserIdByToken = async function(token: string) {
|
|
|
return this.findOne({ tokenHash, expiredAt: { $gt: now } }).select('user');
|
|
|
};
|
|
|
|
|
|
-accessTokenSchema.statics.findTokenByUserId = async function(userId: Types.ObjectId) {
|
|
|
+accessTokenSchema.statics.findTokenByUserId = async function(userId: Types.ObjectId | string) {
|
|
|
const now = new Date();
|
|
|
return this.find({ user: userId, expiredAt: { $gt: now } }).select('_id expiredAt scope description');
|
|
|
};
|
|
|
@@ -111,4 +121,4 @@ accessTokenSchema.methods.isExpired = function() {
|
|
|
return this.expiredAt < new Date();
|
|
|
};
|
|
|
|
|
|
-export const AccessToken = getOrCreateModel<IAccessTokenDocument, IAccessToken>('AccessToken', accessTokenSchema);
|
|
|
+export const AccessToken = getOrCreateModel<IAccessTokenDocument, IAccessTokenModel>('AccessToken', accessTokenSchema);
|