@elysiumjs/themis 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ declare const InvalidSignatureError_base: {
2
+ new (detail?: string, options?: import("@elysiumjs/core").DomainErrorOptions): {
3
+ name: string;
4
+ message: string;
5
+ stack?: string;
6
+ cause?: unknown;
7
+ value?(): import("elysia/types").MaybePromise<unknown>;
8
+ readonly code: "INVALID_SIGNATURE";
9
+ readonly status: 403;
10
+ readonly detail: string | undefined;
11
+ readonly title: string;
12
+ readonly errors: readonly import("@elysiumjs/core").ProblemValidationError[] | undefined;
13
+ readonly retryAfterSeconds: number | undefined;
14
+ readonly extensions: Readonly<Record<string, unknown>>;
15
+ readonly headers: Record<string, string> | undefined;
16
+ readonly type: string;
17
+ extension(): Record<string, unknown>;
18
+ };
19
+ isError(error: unknown): error is Error;
20
+ isError(value: unknown): value is Error;
21
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
22
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
23
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
24
+ stackTraceLimit: number;
25
+ id<const Type extends string>(code: Type): import("elysia").TaggedHTTPError<Type>;
26
+ id<const Type extends string, const S_1 extends number | keyof import("elysia").StatusMap>(code: Type, status: S_1): import("elysia").TaggedHTTPError<Type, {
27
+ readonly status: S_1 extends keyof import("elysia").StatusMap ? import("elysia").StatusMap[S_1] : S_1;
28
+ }>;
29
+ typeBase?: string;
30
+ for<const C extends import("@elysiumjs/core").ProblemCode, const S extends number>(code: C, status: S): any;
31
+ };
32
+ /**
33
+ * Raised when a signed URL was tampered with or has expired. Rendered as a 403 problem.
34
+ * @author Axel Nana <axel.nana@workbud.com>
35
+ */
36
+ export declare class InvalidSignatureError extends InvalidSignatureError_base {
37
+ constructor(expired: boolean);
38
+ }
39
+ export declare namespace SignedUrl {
40
+ /**
41
+ * Signs a URL with HMAC-SHA256: adds `expires` (when asked) and `signature` parameters. The
42
+ * path and every parameter are signed; the origin is not, so that the link works behind any
43
+ * host name.
44
+ * @author Axel Nana <axel.nana@workbud.com>
45
+ * @param url The URL.
46
+ * @param options The secret, and how long the link lives, in seconds.
47
+ * @example
48
+ * ```ts
49
+ * const link = await SignedUrl.sign(`${base}/invoices/42/pdf`, { secret, expiresIn: 3600 });
50
+ * ```
51
+ */
52
+ const sign: (url: string | URL, options: {
53
+ secret: string;
54
+ expiresIn?: number;
55
+ }) => Promise<string>;
56
+ /**
57
+ * Whether a URL carries a valid signature and has not expired.
58
+ * @author Axel Nana <axel.nana@workbud.com>
59
+ */
60
+ const verify: (url: string | URL, options: {
61
+ secret: string;
62
+ }) => Promise<boolean>;
63
+ /**
64
+ * Checks the signature of a URL, such as `request.url` in a handler.
65
+ * @author Axel Nana <axel.nana@workbud.com>
66
+ * @throws {InvalidSignatureError} When the URL was tampered with or has expired (403).
67
+ */
68
+ const assert: (url: string | URL, options: {
69
+ secret: string;
70
+ }) => Promise<void>;
71
+ }
72
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { ThemisConfig } from './config';
2
+ declare const ThemisModule_base: (abstract new () => {
3
+ readonly config: ThemisConfig;
4
+ onInit(): Promise<void> | void;
5
+ onDestroy(): Promise<void> | void;
6
+ onServe(_app: import("elysia").Elysia<any>): Promise<void> | void;
7
+ }) & {
8
+ readonly config: string;
9
+ with(config: Partial<ThemisConfig> | (() => Partial<ThemisConfig> | Promise<Partial<ThemisConfig>>)): import("@elysiumjs/core").ConfiguredModule<ThemisConfig>;
10
+ resolveConfig(input?: Partial<ThemisConfig> | undefined): ThemisConfig;
11
+ register<TConfig_1 = any>(props?: import("@elysiumjs/core").ModuleProps<TConfig_1>): (target: import("@elysiumjs/core").ModuleClass) => void;
12
+ configurable<TConfig extends object>(options?: {
13
+ defaults?: Partial<TConfig>;
14
+ required?: (keyof TConfig)[];
15
+ }): any;
16
+ };
17
+ /**
18
+ * Configures Themis: the secret, the sessions and the guards of `@Auth()`.
19
+ * @author Axel Nana <axel.nana@workbud.com>
20
+ * @example
21
+ * ```ts
22
+ * ThemisModule.with({
23
+ * secret: env.APP_SECRET,
24
+ * session: { store: new RedisSessionStore({ connection: () => Redis.connection() }) },
25
+ * guards: {
26
+ * session: sessionGuard({ user: (id) => users.find(id) }),
27
+ * jwt: jwtGuard({ secret: env.JWT_SECRET })
28
+ * }
29
+ * });
30
+ * ```
31
+ */
32
+ export declare class ThemisModule extends ThemisModule_base {
33
+ }
34
+ export {};
package/dist/totp.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The parameters of TOTP codes. The defaults (6 digits, 30 seconds, SHA-1) are the ones every
3
+ * authenticator app supports.
4
+ * @author Axel Nana <axel.nana@workbud.com>
5
+ */
6
+ export type TotpOptions = {
7
+ digits?: number;
8
+ period?: number;
9
+ algorithm?: 'SHA1' | 'SHA256' | 'SHA512';
10
+ };
11
+ export declare namespace Totp {
12
+ /**
13
+ * Generates a TOTP secret: 20 random bytes as base32, as authenticator apps expect.
14
+ * @author Axel Nana <axel.nana@workbud.com>
15
+ */
16
+ const generateSecret: (bytes?: number) => string;
17
+ /**
18
+ * The `otpauth://` URI of a secret, to show as a QR code.
19
+ * @author Axel Nana <axel.nana@workbud.com>
20
+ * @param options The secret, the issuer (the app name) and the account (such as the email).
21
+ */
22
+ const uri: (options: TotpOptions & {
23
+ secret: string;
24
+ issuer: string;
25
+ account: string;
26
+ }) => string;
27
+ /**
28
+ * The code of a secret at a time (RFC 6238).
29
+ * @author Axel Nana <axel.nana@workbud.com>
30
+ * @param secret The base32 secret.
31
+ * @param options The parameters, and the time in milliseconds (now by default).
32
+ */
33
+ const generate: (secret: string, options?: TotpOptions & {
34
+ time?: number;
35
+ }) => Promise<string>;
36
+ /**
37
+ * Whether a code is the one of the current period, or of `window` periods around it, to allow
38
+ * for clock drift. Compare the returned counter with the last one used to refuse a replay.
39
+ * @author Axel Nana <axel.nana@workbud.com>
40
+ * @param code The code the user typed.
41
+ * @param secret The base32 secret.
42
+ * @param options The parameters, the window (1 by default) and the time.
43
+ * @returns The counter of the matching period, or `null`.
44
+ */
45
+ const verify: (code: string, secret: string, options?: TotpOptions & {
46
+ window?: number;
47
+ time?: number;
48
+ }) => Promise<number | null>;
49
+ }
50
+ export declare namespace BackupCodes {
51
+ /**
52
+ * Generates one-time backup codes, such as `k3m9q-x7t2p`. Show the codes once and store only
53
+ * their hashes.
54
+ * @author Axel Nana <axel.nana@workbud.com>
55
+ * @param count The number of codes. Defaults to 10.
56
+ * @returns The codes, and their hashes in the same order.
57
+ */
58
+ const generate: (count?: number) => Promise<{
59
+ codes: string[];
60
+ hashes: string[];
61
+ }>;
62
+ /**
63
+ * Uses a backup code: checks it against the stored hashes, and returns the hashes left once it
64
+ * is used up. Case, spaces and dashes do not matter.
65
+ * @author Axel Nana <axel.nana@workbud.com>
66
+ * @param code The code the user typed.
67
+ * @param hashes The stored hashes.
68
+ */
69
+ const consume: (code: string, hashes: readonly string[]) => Promise<{
70
+ valid: boolean;
71
+ remaining: string[];
72
+ }>;
73
+ }
package/package.json CHANGED
@@ -1,6 +1,71 @@
1
1
  {
2
2
  "name": "@elysiumjs/themis",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "license": "Apache-2.0",
5
+ "description": "Authentication for the Elysium.js framework: passwords, tokens, sessions, guards, CSRF, TOTP, OAuth and passkeys.",
6
+ "private": false,
7
+ "author": {
8
+ "name": "Axel Nana",
9
+ "email": "axel.nana@workbud.com"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/na2axl/elysiumjs.git",
14
+ "directory": "@elysiumjs/themis"
15
+ },
16
+ "homepage": "https://github.com/na2axl/elysiumjs/tree/main/@elysiumjs/themis#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/na2axl/elysiumjs/issues"
19
+ },
20
+ "scripts": {
21
+ "format": "prettier --write \"./src/**/*.ts\"",
22
+ "clean": "rimraf dist",
23
+ "build:js": "bun build ./src/index.ts ./src/scrypt.ts --outdir ./dist --target browser --packages external --splitting --root ./src --minify-syntax --minify-whitespace",
24
+ "build:ts": "tsc",
25
+ "build": "bun run clean && bun run build:js && bun run build:ts",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "bun run build",
28
+ "test": "bun test",
29
+ "test:coverage": "bun test --coverage"
30
+ },
31
+ "keywords": [
32
+ "elysium",
33
+ "framework",
34
+ "typescript",
35
+ "auth",
36
+ "sessions",
37
+ "jwt",
38
+ "passkeys"
39
+ ],
40
+ "type": "module",
41
+ "module": "dist/index.js",
42
+ "types": "dist/index.d.ts",
43
+ "exports": {
44
+ ".": {
45
+ "types": "./dist/index.d.ts",
46
+ "import": "./dist/index.js"
47
+ },
48
+ "./scrypt": {
49
+ "types": "./dist/scrypt.d.ts",
50
+ "import": "./dist/scrypt.js"
51
+ }
52
+ },
53
+ "files": [
54
+ "dist",
55
+ "CHANGELOG.md"
56
+ ],
57
+ "sideEffects": false,
58
+ "dependencies": {
59
+ "@simplewebauthn/server": "^14.0.3",
60
+ "jose": "^6.2.15",
61
+ "oauth4webapi": "^3.8.8"
62
+ },
63
+ "devDependencies": {
64
+ "@elysiumjs/core": "0.11.0",
65
+ "@elysiumjs/runtime-bun": "0.1.0",
66
+ "elysia": "^2.0.0-rc.1"
67
+ },
68
+ "peerDependencies": {
69
+ "@elysiumjs/core": "^0.11.0"
70
+ }
71
+ }