Last active
March 21, 2023 04:53
-
-
Save Jackman3005/7c018d62cefeb022743ca4ed5e8e2e4d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import crypto from "crypto"; | |
export enum KvdbPermission { | |
None = 0, | |
Read = 1 << 1, | |
Write = 1 << 2, | |
Delete = 1 << 3, | |
Enumerate = 1 << 4, | |
} | |
interface KvdbToken { | |
version: number; | |
expires: number; | |
permission: number; | |
prefix: string; | |
sign: (signingKey: string) => string; | |
} | |
export function createKvdbToken( | |
prefix: string, | |
ttlSeconds: number, | |
...permissions: KvdbPermission[] | |
): KvdbToken { | |
return { | |
version: 1, | |
expires: Math.floor(Date.now() / 1000) + ttlSeconds, | |
permission: permissions | |
.map((p) => p.valueOf()) | |
.reduce((p, c) => p | c, KvdbPermission.None.valueOf()), | |
prefix, | |
sign(signingKey: string) { | |
/** | |
* Token Buffer Bytes Layout: | |
* 0: version (1 byte) | |
* 1-4: expiration timestamp (4 bytes - Big Endian Byte Order) | |
* 5: permission (1 byte) | |
* 6-: prefix (variable length) | |
*/ | |
const tokenBuffer = new ArrayBuffer(6 + this.prefix.length); | |
const dataView = new DataView(tokenBuffer); | |
dataView.setUint8(0, this.version); | |
dataView.setUint32(1, this.expires, false); // `false` writes value in big endianness order | |
dataView.setUint8(5, this.permission); | |
const byteIndexOfPrefixStart = 6; | |
for (let i = 0; i < this.prefix.length; i++) { | |
const byteOffset = i + byteIndexOfPrefixStart; | |
dataView.setUint8(byteOffset, this.prefix.charCodeAt(i)); | |
} | |
const base64Token = Buffer.from(tokenBuffer) | |
.toString("base64url") | |
.replaceAll("=", ""); | |
const signature = crypto | |
.createHmac("sha256", signingKey) | |
.update(new Uint8Array(tokenBuffer)) | |
.digest("base64url") | |
.replaceAll("=", ""); | |
return `${base64Token}.${signature}`; | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is an example using the code above to create & sign an access token for temporary (60 seconds) write access to keys with the prefix: "users:1:"