mirror of
https://github.com/usatiuk/photos.git
synced 2025-10-28 23:37:48 +01:00
cache jwt access tokens
This commit is contained in:
@@ -36,6 +36,7 @@ export interface IPhotoJSON {
|
||||
format: string;
|
||||
createdAt: number;
|
||||
editedAt: number;
|
||||
shotAt: number;
|
||||
}
|
||||
|
||||
export interface IPhotoReqJSON extends IPhotoJSON {
|
||||
@@ -62,6 +63,15 @@ export class Photo extends BaseEntity {
|
||||
@IsMimeType()
|
||||
public format: string;
|
||||
|
||||
@Column({ type: "varchar", length: 500 })
|
||||
public accessToken: string;
|
||||
|
||||
@Column({ type: "timestamp", default: null })
|
||||
public accessTokenExpiry: Date;
|
||||
|
||||
@Column({ type: "timestamp", default: null })
|
||||
public shotAt: Date;
|
||||
|
||||
@Column({ type: "timestamp", default: null })
|
||||
public createdAt: Date;
|
||||
|
||||
@@ -115,17 +125,31 @@ export class Photo extends BaseEntity {
|
||||
super();
|
||||
this.createdAt = new Date();
|
||||
this.editedAt = this.createdAt;
|
||||
this.shotAt = this.createdAt;
|
||||
this.accessTokenExpiry = this.createdAt;
|
||||
this.accessToken = "";
|
||||
this.hash = hash;
|
||||
this.format = format;
|
||||
this.size = size;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public getJWTToken(): string {
|
||||
return jwt.sign(this.toJSON(), config.jwtSecret, {
|
||||
expiresIn: "1h",
|
||||
algorithm: "HS256",
|
||||
});
|
||||
public async getJWTToken(): Promise<string> {
|
||||
const now = new Date().getTime();
|
||||
const tokenExpiryOld = this.accessTokenExpiry.getTime();
|
||||
// If expires in more than 10 minutes then get from cache
|
||||
if (tokenExpiryOld - now - 60 * 10 * 1000 > 0) {
|
||||
return this.accessToken;
|
||||
} else {
|
||||
const token = jwt.sign(this.toJSON(), config.jwtSecret, {
|
||||
expiresIn: "1h",
|
||||
algorithm: "HS256",
|
||||
});
|
||||
this.accessToken = token;
|
||||
this.accessTokenExpiry = new Date(now + 60 * 60 * 1000);
|
||||
await this.save();
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
public toJSON(): IPhotoJSON {
|
||||
@@ -137,19 +161,12 @@ export class Photo extends BaseEntity {
|
||||
format: this.format,
|
||||
createdAt: this.createdAt.getTime(),
|
||||
editedAt: this.editedAt.getTime(),
|
||||
shotAt: this.shotAt.getTime(),
|
||||
};
|
||||
}
|
||||
|
||||
public toReqJSON(): IPhotoReqJSON {
|
||||
return {
|
||||
id: this.id,
|
||||
user: this.user.id,
|
||||
hash: this.hash,
|
||||
size: this.size,
|
||||
format: this.format,
|
||||
createdAt: this.createdAt.getTime(),
|
||||
editedAt: this.editedAt.getTime(),
|
||||
accessToken: this.getJWTToken(),
|
||||
};
|
||||
public async toReqJSON(): Promise<IPhotoReqJSON> {
|
||||
const token = await this.getJWTToken();
|
||||
return { ...this.toJSON(), accessToken: token };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ photosRouter.post("/photos/new", async (ctx) => {
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photo.toReqJSON(),
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosNewRespBody;
|
||||
return;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ photosRouter.post("/photos/new", async (ctx) => {
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photo.toReqJSON(),
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosNewRespBody;
|
||||
});
|
||||
|
||||
@@ -115,7 +115,7 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
||||
}
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photo.toReqJSON(),
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosUploadRespBody;
|
||||
});
|
||||
|
||||
@@ -172,9 +172,13 @@ photosRouter.get("/photos/list", async (ctx) => {
|
||||
|
||||
const photos = await Photo.find({ user });
|
||||
|
||||
const photosList: IPhotoReqJSON[] = await Promise.all(
|
||||
photos.map(async (photo) => await photo.toReqJSON()),
|
||||
);
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photos.map((photo) => photo.toReqJSON()),
|
||||
data: photosList,
|
||||
} as IPhotosListRespBody;
|
||||
});
|
||||
|
||||
@@ -203,7 +207,7 @@ photosRouter.get("/photos/byID/:id", async (ctx) => {
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photo.toReqJSON(),
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosByIDGetRespBody;
|
||||
});
|
||||
|
||||
@@ -288,7 +292,7 @@ photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = photo.getJWTToken();
|
||||
const token = await photo.getJWTToken();
|
||||
|
||||
ctx.body = { error: false, data: token } as IPhotosGetShowTokenByID;
|
||||
});
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("photos", function () {
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
|
||||
const usedPhoto = seed.dogPhoto.toReqJSON();
|
||||
const usedPhoto = await seed.dogPhoto.toReqJSON();
|
||||
|
||||
expect(photo).to.deep.equal(usedPhoto);
|
||||
});
|
||||
@@ -126,7 +126,7 @@ describe("photos", function () {
|
||||
);
|
||||
|
||||
const tokenSelfSigned = jwt.sign(
|
||||
seed.dogPhoto.toReqJSON(),
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
config.jwtSecret,
|
||||
{
|
||||
expiresIn: "1m",
|
||||
@@ -142,9 +142,13 @@ describe("photos", function () {
|
||||
});
|
||||
|
||||
it("should not show a photo using expired access token", async function () {
|
||||
const token = jwt.sign(seed.dogPhoto.toReqJSON(), config.jwtSecret, {
|
||||
expiresIn: "0s",
|
||||
});
|
||||
const token = jwt.sign(
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
config.jwtSecret,
|
||||
{
|
||||
expiresIn: "0s",
|
||||
},
|
||||
);
|
||||
|
||||
const response = await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
||||
@@ -239,7 +243,14 @@ describe("photos", function () {
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
.expect(400);
|
||||
.expect(200);
|
||||
|
||||
const dbPhoto = await Photo.find({
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto).to.have.lengthOf(1);
|
||||
});
|
||||
|
||||
it("should not upload a photo twice", async function () {
|
||||
@@ -488,8 +499,8 @@ describe("photos", function () {
|
||||
const photos = response.body.data as IPhotoReqJSON[];
|
||||
|
||||
const userPhotos = [
|
||||
seed.dogPhoto.toReqJSON(),
|
||||
seed.catPhoto.toReqJSON(),
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
await seed.catPhoto.toReqJSON(),
|
||||
];
|
||||
|
||||
expect(photos).to.deep.equal(userPhotos);
|
||||
|
||||
Reference in New Issue
Block a user