Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

Commit

Permalink
feat(tokens): Add a modify_meta script.
Browse files Browse the repository at this point in the history
  • Loading branch information
Blckbrry-Pi committed Jul 2, 2024
1 parent 801efc4 commit d2012c6
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 69 deletions.
100 changes: 52 additions & 48 deletions modules/tokens/module.json
Original file line number Diff line number Diff line change
@@ -1,50 +1,54 @@
{
"name": "Tokens",
"description": "Create & verify tokens for authorization purposes.",
"icon": "lock",
"tags": [
"core",
"utility"
],
"authors": [
"rivet-gg",
"NathanFlurry"
],
"status": "stable",
"scripts": {
"create": {
"name": "Create Token"
},
"fetch": {
"name": "Fetch Token",
"description": "Get a token by its ID."
},
"fetch_by_token": {
"name": "Fetch by Token",
"description": "Get a token by its secret token."
},
"revoke": {
"name": "Revoke Token",
"description": "Revoke a token, preventing it from being used again."
},
"validate": {
"name": "Validate Token",
"description": "Validate a token. Throws an error if the token is invalid."
},
"extend": {
"name": "Extend Token",
"description": "Extend or remove the expiration date of a token. (Only works on valid tokens.)"
}
},
"errors": {
"token_not_found": {
"name": "Token Not Found"
},
"token_revoked": {
"name": "Token Revoked"
},
"token_expired": {
"name": "Token Expired"
}
}
"name": "Tokens",
"description": "Create & verify tokens for authorization purposes.",
"icon": "lock",
"tags": [
"core",
"utility"
],
"authors": [
"rivet-gg",
"NathanFlurry"
],
"status": "stable",
"scripts": {
"create": {
"name": "Create Token"
},
"fetch": {
"name": "Fetch Token",
"description": "Get a token by its ID."
},
"fetch_by_token": {
"name": "Fetch by Token",
"description": "Get a token by its secret token."
},
"revoke": {
"name": "Revoke Token",
"description": "Revoke a token, preventing it from being used again."
},
"validate": {
"name": "Validate Token",
"description": "Validate a token. Throws an error if the token is invalid."
},
"extend": {
"name": "Extend Token",
"description": "Extend or remove the expiration date of a token. (Only works on valid tokens.)"
},
"modify_meta": {
"name": "Modify Token Metadata",
"description": "Modify the token's associated metadata, additionally returning the old metadata. (Only works on valid tokens.)"
}
},
"errors": {
"token_not_found": {
"name": "Token Not Found"
},
"token_revoked": {
"name": "Token Revoked"
},
"token_expired": {
"name": "Token Expired"
}
}
}
34 changes: 17 additions & 17 deletions modules/tokens/scripts/extend.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ScriptContext } from "../module.gen.ts";
import { TokenWithSecret, tokenFromRow } from "../utils/types.ts";
import { tokenFromRow, TokenWithSecret } from "../utils/types.ts";

export interface Request {
token: string;
newExpiration: string | null;
token: string;
newExpiration: string | null;
}

export interface Response {
Expand All @@ -14,22 +14,22 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
// Ensure the token hasn't expired or been revoked yet
const { token } = await ctx.modules.tokens.validate({
token: req.token,
});
// Ensure the token hasn't expired or been revoked yet
const { token } = await ctx.modules.tokens.validate({
token: req.token,
});

// Update the token's expiration date
const newToken = await ctx.db.token.update({
where: {
id: token.id,
},
data: {
expireAt: req.newExpiration,
},
});
// Update the token's expiration date
const newToken = await ctx.db.token.update({
where: {
id: token.id,
},
data: {
expireAt: req.newExpiration,
},
});

// Return the updated token
// Return the updated token
return {
token: tokenFromRow(newToken),
};
Expand Down
38 changes: 38 additions & 0 deletions modules/tokens/scripts/modify_meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ScriptContext } from "../module.gen.ts";
import { Token, tokenFromRow } from "../utils/types.ts";

export interface Request {
token: string;
newMeta: { [key: string]: any };
}

export interface Response {
token: Token;
oldMeta: { [key: string]: any };
}

export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
// Ensure the token hasn't expired or been revoked yet
const { token } = await ctx.modules.tokens.validate({
token: req.token,
});

// Update the token's expiration date
const newToken = await ctx.db.token.update({
where: {
id: token.id,
},
data: {
meta: req.newMeta,
},
});

// Return the updated token
return {
token: tokenFromRow(newToken),
oldMeta: token.meta,
};
}
2 changes: 1 addition & 1 deletion modules/tokens/scripts/revoke.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Prisma, ScriptContext } from "../module.gen.ts";
import { ScriptContext } from "../module.gen.ts";

export interface Request {
tokenIds: string[];
Expand Down
42 changes: 42 additions & 0 deletions modules/tokens/tests/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { test, TestContext } from "../module.gen.ts";
import {
assertEquals,
assertExists,
assertRejects,
} from "https://deno.land/[email protected]/assert/mod.ts";
import { RuntimeError } from "../module.gen.ts";

const METADATA_PRE = { state: "beforeModify" };
const METADATA_POST = { state: "afterModify" };

test("modify_meta", async (ctx: TestContext) => {
const { token } = await ctx.modules.tokens.create({
type: "test",
meta: METADATA_PRE,
});

const { tokens: [tokenPre] } = await ctx.modules.tokens.fetch({
tokenIds: [token.id],
});
assertExists(tokenPre);
// assertEquals(typeof tokenPre.meta, "string");
assertEquals(tokenPre.meta, METADATA_PRE);

const { oldMeta: fetchedOldMeta, token: tokenPost } = await ctx.modules.tokens
.modifyMeta({
token: token.token,
newMeta: METADATA_POST,
});
assertExists(tokenPost);
assertEquals(tokenPost.meta, METADATA_POST);
assertEquals(fetchedOldMeta, METADATA_PRE);

await ctx.modules.tokens.revoke({ tokenIds: [token.id] });

const err = await assertRejects(() =>
ctx.modules.tokens.modifyMeta({
token: token.token,
newMeta: METADATA_POST,
}), RuntimeError);
assertEquals(err.code, "token_revoked");
});
4 changes: 2 additions & 2 deletions modules/tokens/tests/validate.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RuntimeError, test, TestContext } from "../module.gen.ts";
import {
assertEquals,
assertRejects,
assertGreater,
assertRejects,
} from "https://deno.land/[email protected]/assert/mod.ts";

test(
Expand Down Expand Up @@ -97,6 +97,6 @@ test(
}, {
...token,
expireAt: null,
})
});
},
);
5 changes: 5 additions & 0 deletions modules/tokens/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export function tokenFromRow(
): TokenWithSecret {
return {
...row,
// NOTE: Not sure why this is necessary— prisma seems to be stringifying
// all JSON values before returning them.
//
// Should look into more.
meta: row.meta ? JSON.parse(row.meta.toString()) : row.meta,
createdAt: row.createdAt.toISOString(),
expireAt: row.expireAt?.toISOString() ?? null,
revokedAt: row.revokedAt?.toISOString() ?? null,
Expand Down
2 changes: 1 addition & 1 deletion tests/basic/deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d2012c6

Please sign in to comment.