unotoken 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.
Files changed (122) hide show
  1. package/README.md +360 -0
  2. package/dist/cli.d.ts +17 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +1207 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/client.d.ts +15 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +15 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/db.d.ts +52 -0
  11. package/dist/db.d.ts.map +1 -0
  12. package/dist/db.js +97 -0
  13. package/dist/db.js.map +1 -0
  14. package/dist/dotenv.d.ts +69 -0
  15. package/dist/dotenv.d.ts.map +1 -0
  16. package/dist/dotenv.js +115 -0
  17. package/dist/dotenv.js.map +1 -0
  18. package/dist/env-mapper.d.ts +55 -0
  19. package/dist/env-mapper.d.ts.map +1 -0
  20. package/dist/env-mapper.js +97 -0
  21. package/dist/env-mapper.js.map +1 -0
  22. package/dist/exec.d.ts +80 -0
  23. package/dist/exec.d.ts.map +1 -0
  24. package/dist/exec.js +214 -0
  25. package/dist/exec.js.map +1 -0
  26. package/dist/index.d.ts +12 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +43 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/oauth/commands.d.ts +151 -0
  31. package/dist/oauth/commands.d.ts.map +1 -0
  32. package/dist/oauth/commands.js +322 -0
  33. package/dist/oauth/commands.js.map +1 -0
  34. package/dist/oauth/config.d.ts +84 -0
  35. package/dist/oauth/config.d.ts.map +1 -0
  36. package/dist/oauth/config.js +156 -0
  37. package/dist/oauth/config.js.map +1 -0
  38. package/dist/oauth/crypto-helpers.d.ts +44 -0
  39. package/dist/oauth/crypto-helpers.d.ts.map +1 -0
  40. package/dist/oauth/crypto-helpers.js +94 -0
  41. package/dist/oauth/crypto-helpers.js.map +1 -0
  42. package/dist/oauth/device-secret.d.ts +57 -0
  43. package/dist/oauth/device-secret.d.ts.map +1 -0
  44. package/dist/oauth/device-secret.js +106 -0
  45. package/dist/oauth/device-secret.js.map +1 -0
  46. package/dist/oauth/flow.d.ts +112 -0
  47. package/dist/oauth/flow.d.ts.map +1 -0
  48. package/dist/oauth/flow.js +255 -0
  49. package/dist/oauth/flow.js.map +1 -0
  50. package/dist/oauth/index.d.ts +18 -0
  51. package/dist/oauth/index.d.ts.map +1 -0
  52. package/dist/oauth/index.js +24 -0
  53. package/dist/oauth/index.js.map +1 -0
  54. package/dist/oauth/key-wrap.d.ts +146 -0
  55. package/dist/oauth/key-wrap.d.ts.map +1 -0
  56. package/dist/oauth/key-wrap.js +275 -0
  57. package/dist/oauth/key-wrap.js.map +1 -0
  58. package/dist/oauth/pkce.d.ts +29 -0
  59. package/dist/oauth/pkce.d.ts.map +1 -0
  60. package/dist/oauth/pkce.js +34 -0
  61. package/dist/oauth/pkce.js.map +1 -0
  62. package/dist/oauth/provider.d.ts +79 -0
  63. package/dist/oauth/provider.d.ts.map +1 -0
  64. package/dist/oauth/provider.js +10 -0
  65. package/dist/oauth/provider.js.map +1 -0
  66. package/dist/oauth/providers/github.d.ts +75 -0
  67. package/dist/oauth/providers/github.d.ts.map +1 -0
  68. package/dist/oauth/providers/github.js +119 -0
  69. package/dist/oauth/providers/github.js.map +1 -0
  70. package/dist/oauth/providers/google.d.ts +115 -0
  71. package/dist/oauth/providers/google.d.ts.map +1 -0
  72. package/dist/oauth/providers/google.js +285 -0
  73. package/dist/oauth/providers/google.js.map +1 -0
  74. package/dist/sdk.d.ts +8 -0
  75. package/dist/sdk.d.ts.map +1 -0
  76. package/dist/sdk.js +8 -0
  77. package/dist/sdk.js.map +1 -0
  78. package/dist/server.d.ts +33 -0
  79. package/dist/server.d.ts.map +1 -0
  80. package/dist/server.js +287 -0
  81. package/dist/server.js.map +1 -0
  82. package/dist/signatures/approval-codes.d.ts +192 -0
  83. package/dist/signatures/approval-codes.d.ts.map +1 -0
  84. package/dist/signatures/approval-codes.js +407 -0
  85. package/dist/signatures/approval-codes.js.map +1 -0
  86. package/dist/signatures/commands.d.ts +108 -0
  87. package/dist/signatures/commands.d.ts.map +1 -0
  88. package/dist/signatures/commands.js +270 -0
  89. package/dist/signatures/commands.js.map +1 -0
  90. package/dist/signatures/devices.d.ts +165 -0
  91. package/dist/signatures/devices.d.ts.map +1 -0
  92. package/dist/signatures/devices.js +344 -0
  93. package/dist/signatures/devices.js.map +1 -0
  94. package/dist/signatures/email-config.d.ts +102 -0
  95. package/dist/signatures/email-config.d.ts.map +1 -0
  96. package/dist/signatures/email-config.js +188 -0
  97. package/dist/signatures/email-config.js.map +1 -0
  98. package/dist/signatures/email.d.ts +106 -0
  99. package/dist/signatures/email.d.ts.map +1 -0
  100. package/dist/signatures/email.js +180 -0
  101. package/dist/signatures/email.js.map +1 -0
  102. package/dist/signatures/fingerprint.d.ts +70 -0
  103. package/dist/signatures/fingerprint.d.ts.map +1 -0
  104. package/dist/signatures/fingerprint.js +123 -0
  105. package/dist/signatures/fingerprint.js.map +1 -0
  106. package/dist/signatures/guard.d.ts +118 -0
  107. package/dist/signatures/guard.d.ts.map +1 -0
  108. package/dist/signatures/guard.js +310 -0
  109. package/dist/signatures/guard.js.map +1 -0
  110. package/dist/signatures/resend.d.ts +84 -0
  111. package/dist/signatures/resend.d.ts.map +1 -0
  112. package/dist/signatures/resend.js +248 -0
  113. package/dist/signatures/resend.js.map +1 -0
  114. package/dist/token-requests.d.ts +80 -0
  115. package/dist/token-requests.d.ts.map +1 -0
  116. package/dist/token-requests.js +201 -0
  117. package/dist/token-requests.js.map +1 -0
  118. package/dist/tokens.d.ts +80 -0
  119. package/dist/tokens.d.ts.map +1 -0
  120. package/dist/tokens.js +150 -0
  121. package/dist/tokens.js.map +1 -0
  122. package/package.json +62 -0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Email verification flow for unotoken device signatures.
3
+ *
4
+ * Orchestrates the email verification process:
5
+ * 1. User provides their email address
6
+ * 2. A 6-digit code is generated and sent via Resend
7
+ * 3. User enters the code to verify ownership
8
+ * 4. On success, email is saved to email-config.json as verified
9
+ *
10
+ * This module connects email-config (persistence) and resend (sending)
11
+ * into a cohesive verification flow.
12
+ *
13
+ * @module
14
+ */
15
+ import { type EmailConfig } from './email-config.js';
16
+ export interface PendingVerification {
17
+ /** The email address being verified */
18
+ email: string;
19
+ /** SHA-256 hash of the code (never store plaintext) */
20
+ codeHash: string;
21
+ /** When the code was generated (ISO 8601) */
22
+ createdAt: string;
23
+ /** When the code expires (ISO 8601) */
24
+ expiresAt: string;
25
+ /** Number of verification attempts made */
26
+ attempts: number;
27
+ /** Maximum allowed attempts */
28
+ maxAttempts: number;
29
+ }
30
+ export interface VerificationResult {
31
+ /** Whether the code was valid and email is now verified */
32
+ success: boolean;
33
+ /** Reason for failure (if not successful) */
34
+ reason?: 'invalid_code' | 'expired' | 'max_attempts' | 'no_pending';
35
+ /** Number of remaining attempts (if applicable) */
36
+ remainingAttempts?: number;
37
+ }
38
+ export interface InitiateVerificationResult {
39
+ /** Whether the verification email was sent successfully */
40
+ sent: boolean;
41
+ /** Error message if sending failed */
42
+ error?: string;
43
+ /** The pending verification state (for passing to verifyCode) */
44
+ pending?: PendingVerification;
45
+ }
46
+ /**
47
+ * Generate a cryptographically random 6-digit code.
48
+ *
49
+ * Uses crypto.randomInt (not Math.random) for security.
50
+ *
51
+ * @returns A 6-digit string (zero-padded)
52
+ */
53
+ export declare function generateVerificationCode(): string;
54
+ /**
55
+ * Hash a verification code with SHA-256.
56
+ *
57
+ * Codes are always stored as hashes, never plaintext.
58
+ *
59
+ * @param code - The plaintext 6-digit code
60
+ * @returns SHA-256 hex digest
61
+ */
62
+ export declare function hashCode(code: string): string;
63
+ /**
64
+ * Initiate email verification by sending a code.
65
+ *
66
+ * @param email - The email address to verify
67
+ * @param deviceFingerprint - Current device fingerprint (for rate limiting and context)
68
+ * @param deviceName - Current device name (for email context)
69
+ * @param baseDir - Optional base directory for config files
70
+ * @returns Result with sent status and pending verification state
71
+ */
72
+ export declare function initiateVerification(email: string, deviceFingerprint: string, deviceName: string, baseDir?: string): Promise<InitiateVerificationResult>;
73
+ /**
74
+ * Verify a code against a pending verification.
75
+ *
76
+ * @param pending - The pending verification state
77
+ * @param userCode - The code entered by the user
78
+ * @returns Verification result
79
+ */
80
+ export declare function verifyCode(pending: PendingVerification, userCode: string): VerificationResult;
81
+ /**
82
+ * Complete email verification by saving the config.
83
+ *
84
+ * Call this after verifyCode returns success.
85
+ *
86
+ * @param email - The verified email address
87
+ * @param resendApiKey - Optional custom Resend API key to persist
88
+ * @param baseDir - Optional base directory for config files
89
+ * @returns The saved email config
90
+ */
91
+ export declare function completeVerification(email: string, resendApiKey?: string, baseDir?: string): EmailConfig;
92
+ /**
93
+ * Check if the code expiry time has passed.
94
+ *
95
+ * @param pending - The pending verification
96
+ * @returns true if the code has expired
97
+ */
98
+ export declare function isCodeExpired(pending: PendingVerification): boolean;
99
+ /**
100
+ * Check if max attempts have been reached.
101
+ *
102
+ * @param pending - The pending verification
103
+ * @returns true if no more attempts are allowed
104
+ */
105
+ export declare function isMaxAttemptsReached(pending: PendingVerification): boolean;
106
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../src/signatures/email.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAoB3B,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,YAAY,CAAC;IACpE,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,IAAI,EAAE,OAAO,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAID;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAGjD;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAID;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,0BAA0B,CAAC,CAwDrC;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,MAAM,GACf,kBAAkB,CA2BpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,GACf,WAAW,CAqBb;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAE1E"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Email verification flow for unotoken device signatures.
3
+ *
4
+ * Orchestrates the email verification process:
5
+ * 1. User provides their email address
6
+ * 2. A 6-digit code is generated and sent via Resend
7
+ * 3. User enters the code to verify ownership
8
+ * 4. On success, email is saved to email-config.json as verified
9
+ *
10
+ * This module connects email-config (persistence) and resend (sending)
11
+ * into a cohesive verification flow.
12
+ *
13
+ * @module
14
+ */
15
+ import { randomInt, createHash } from 'node:crypto';
16
+ import { loadEmailConfig, saveEmailConfig, isValidEmail, } from './email-config.js';
17
+ import { sendApprovalEmail, isRateLimited, } from './resend.js';
18
+ // ─── Constants ──────────────────────────────────────────────────────
19
+ /** Code length (6 digits) */
20
+ const CODE_LENGTH = 6;
21
+ /** Code expiry in milliseconds (5 minutes) */
22
+ const CODE_EXPIRY_MS = 5 * 60 * 1000;
23
+ /** Maximum verification attempts per code */
24
+ const MAX_ATTEMPTS = 3;
25
+ // ─── Code Generation ────────────────────────────────────────────────
26
+ /**
27
+ * Generate a cryptographically random 6-digit code.
28
+ *
29
+ * Uses crypto.randomInt (not Math.random) for security.
30
+ *
31
+ * @returns A 6-digit string (zero-padded)
32
+ */
33
+ export function generateVerificationCode() {
34
+ const code = randomInt(0, 10 ** CODE_LENGTH);
35
+ return code.toString().padStart(CODE_LENGTH, '0');
36
+ }
37
+ /**
38
+ * Hash a verification code with SHA-256.
39
+ *
40
+ * Codes are always stored as hashes, never plaintext.
41
+ *
42
+ * @param code - The plaintext 6-digit code
43
+ * @returns SHA-256 hex digest
44
+ */
45
+ export function hashCode(code) {
46
+ return createHash('sha256').update(code).digest('hex');
47
+ }
48
+ // ─── Verification Flow ──────────────────────────────────────────────
49
+ /**
50
+ * Initiate email verification by sending a code.
51
+ *
52
+ * @param email - The email address to verify
53
+ * @param deviceFingerprint - Current device fingerprint (for rate limiting and context)
54
+ * @param deviceName - Current device name (for email context)
55
+ * @param baseDir - Optional base directory for config files
56
+ * @returns Result with sent status and pending verification state
57
+ */
58
+ export async function initiateVerification(email, deviceFingerprint, deviceName, baseDir) {
59
+ // Validate email format
60
+ if (!isValidEmail(email)) {
61
+ return {
62
+ sent: false,
63
+ error: `Invalid email address: ${email}`,
64
+ };
65
+ }
66
+ // Check rate limit
67
+ if (isRateLimited(deviceFingerprint)) {
68
+ return {
69
+ sent: false,
70
+ error: 'Rate limit exceeded. Maximum 3 verification emails per hour. Please wait before trying again.',
71
+ };
72
+ }
73
+ // Generate code
74
+ const code = generateVerificationCode();
75
+ const codeHash = hashCode(code);
76
+ const now = new Date();
77
+ const expiresAt = new Date(now.getTime() + CODE_EXPIRY_MS);
78
+ // Build context for the email
79
+ const context = {
80
+ deviceName,
81
+ timestamp: now.toISOString(),
82
+ };
83
+ // Send the email
84
+ const result = await sendApprovalEmail(email, code, context, deviceFingerprint, baseDir);
85
+ if (!result.success) {
86
+ return {
87
+ sent: false,
88
+ error: result.error ?? 'Failed to send verification email',
89
+ };
90
+ }
91
+ // Create pending verification state
92
+ const pending = {
93
+ email,
94
+ codeHash,
95
+ createdAt: now.toISOString(),
96
+ expiresAt: expiresAt.toISOString(),
97
+ attempts: 0,
98
+ maxAttempts: MAX_ATTEMPTS,
99
+ };
100
+ return { sent: true, pending };
101
+ }
102
+ /**
103
+ * Verify a code against a pending verification.
104
+ *
105
+ * @param pending - The pending verification state
106
+ * @param userCode - The code entered by the user
107
+ * @returns Verification result
108
+ */
109
+ export function verifyCode(pending, userCode) {
110
+ // Check expiry
111
+ const now = new Date();
112
+ const expiresAt = new Date(pending.expiresAt);
113
+ if (now > expiresAt) {
114
+ return { success: false, reason: 'expired' };
115
+ }
116
+ // Check max attempts
117
+ if (pending.attempts >= pending.maxAttempts) {
118
+ return { success: false, reason: 'max_attempts' };
119
+ }
120
+ // Increment attempts
121
+ pending.attempts += 1;
122
+ // Verify code hash
123
+ const userHash = hashCode(userCode.trim());
124
+ if (userHash !== pending.codeHash) {
125
+ const remaining = pending.maxAttempts - pending.attempts;
126
+ if (remaining <= 0) {
127
+ return { success: false, reason: 'max_attempts', remainingAttempts: 0 };
128
+ }
129
+ return { success: false, reason: 'invalid_code', remainingAttempts: remaining };
130
+ }
131
+ return { success: true };
132
+ }
133
+ /**
134
+ * Complete email verification by saving the config.
135
+ *
136
+ * Call this after verifyCode returns success.
137
+ *
138
+ * @param email - The verified email address
139
+ * @param resendApiKey - Optional custom Resend API key to persist
140
+ * @param baseDir - Optional base directory for config files
141
+ * @returns The saved email config
142
+ */
143
+ export function completeVerification(email, resendApiKey, baseDir) {
144
+ const config = {
145
+ email,
146
+ verified: true,
147
+ verifiedAt: new Date().toISOString(),
148
+ };
149
+ if (resendApiKey) {
150
+ config.resendApiKey = resendApiKey;
151
+ }
152
+ // Preserve existing custom Resend key if not explicitly provided
153
+ if (!resendApiKey) {
154
+ const existing = loadEmailConfig(baseDir);
155
+ if (existing?.resendApiKey) {
156
+ config.resendApiKey = existing.resendApiKey;
157
+ }
158
+ }
159
+ saveEmailConfig(config, baseDir);
160
+ return config;
161
+ }
162
+ /**
163
+ * Check if the code expiry time has passed.
164
+ *
165
+ * @param pending - The pending verification
166
+ * @returns true if the code has expired
167
+ */
168
+ export function isCodeExpired(pending) {
169
+ return new Date() > new Date(pending.expiresAt);
170
+ }
171
+ /**
172
+ * Check if max attempts have been reached.
173
+ *
174
+ * @param pending - The pending verification
175
+ * @returns true if no more attempts are allowed
176
+ */
177
+ export function isMaxAttemptsReached(pending) {
178
+ return pending.attempts >= pending.maxAttempts;
179
+ }
180
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/signatures/email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Device fingerprinting for unotoken device signatures.
3
+ *
4
+ * Generates a stable, unique fingerprint for the current machine by combining:
5
+ * 1. Machine identity (hostname + OS platform + username)
6
+ * 2. A per-install random salt stored at ~/.yokotoken/device-install-id
7
+ *
8
+ * The per-install salt ensures that even identical VMs or containers get
9
+ * different fingerprints. The machine identity ensures that the same install
10
+ * on the same machine always produces the same fingerprint (deterministic).
11
+ *
12
+ * For cloud/container environments, each new container instance will generate
13
+ * a new device-install-id and thus a new fingerprint -- this is intentional,
14
+ * as each container is treated as a separate device.
15
+ *
16
+ * @module
17
+ */
18
+ /**
19
+ * Get the path to the device-install-id file.
20
+ *
21
+ * @param baseDir - Optional base directory (default: ~/.yokotoken)
22
+ * @returns Absolute path to device-install-id
23
+ */
24
+ export declare function getInstallIdPath(baseDir?: string): string;
25
+ /**
26
+ * Read or create the per-install random salt.
27
+ *
28
+ * On first call, generates a 32-byte random value and persists it.
29
+ * On subsequent calls, reads the persisted value.
30
+ *
31
+ * @param baseDir - Optional base directory (default: ~/.yokotoken)
32
+ * @returns The install ID as a hex string
33
+ */
34
+ export declare function ensureInstallId(baseDir?: string): string;
35
+ /**
36
+ * Collect machine identity components.
37
+ *
38
+ * Returns a deterministic string derived from the machine's hostname,
39
+ * OS platform, and current username. This provides a "best effort"
40
+ * machine identity that is stable across restarts.
41
+ *
42
+ * @returns A colon-separated identity string
43
+ */
44
+ export declare function getMachineIdentity(): string;
45
+ /**
46
+ * Generate a stable device fingerprint.
47
+ *
48
+ * The fingerprint is a SHA-256 hash of:
49
+ * machineIdentity + ":" + installId
50
+ *
51
+ * Properties:
52
+ * - Deterministic: same machine + same install-id = same fingerprint
53
+ * - Unique across machines: different hostname/OS/username = different hash
54
+ * - Unique across installs: different install-id = different hash (even on same machine)
55
+ * - Not reversible: SHA-256 hash cannot reveal machine details
56
+ *
57
+ * @param baseDir - Optional base directory for the install-id file (default: ~/.yokotoken)
58
+ * @returns A 64-character hex string (SHA-256 hash)
59
+ */
60
+ export declare function generateDeviceFingerprint(baseDir?: string): string;
61
+ /**
62
+ * Generate a user-friendly device name from system info.
63
+ *
64
+ * Format: "{username}@{hostname}" — human-readable but not guaranteed unique.
65
+ * Used as the default display name for a device in the known_devices registry.
66
+ *
67
+ * @returns A human-friendly device name string
68
+ */
69
+ export declare function getDefaultDeviceName(): string;
70
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/signatures/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAeH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAID;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAW7C"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Device fingerprinting for unotoken device signatures.
3
+ *
4
+ * Generates a stable, unique fingerprint for the current machine by combining:
5
+ * 1. Machine identity (hostname + OS platform + username)
6
+ * 2. A per-install random salt stored at ~/.yokotoken/device-install-id
7
+ *
8
+ * The per-install salt ensures that even identical VMs or containers get
9
+ * different fingerprints. The machine identity ensures that the same install
10
+ * on the same machine always produces the same fingerprint (deterministic).
11
+ *
12
+ * For cloud/container environments, each new container instance will generate
13
+ * a new device-install-id and thus a new fingerprint -- this is intentional,
14
+ * as each container is treated as a separate device.
15
+ *
16
+ * @module
17
+ */
18
+ import { createHash, randomBytes } from 'node:crypto';
19
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
20
+ import { hostname, platform, userInfo } from 'node:os';
21
+ import path from 'node:path';
22
+ import { getDeviceDir } from '../oauth/device-secret.js';
23
+ // ─── Constants ──────────────────────────────────────────────────────
24
+ const INSTALL_ID_FILENAME = 'device-install-id';
25
+ const INSTALL_ID_BYTES = 32;
26
+ // ─── Install ID (per-install salt) ──────────────────────────────────
27
+ /**
28
+ * Get the path to the device-install-id file.
29
+ *
30
+ * @param baseDir - Optional base directory (default: ~/.yokotoken)
31
+ * @returns Absolute path to device-install-id
32
+ */
33
+ export function getInstallIdPath(baseDir) {
34
+ return path.join(baseDir ?? getDeviceDir(), INSTALL_ID_FILENAME);
35
+ }
36
+ /**
37
+ * Read or create the per-install random salt.
38
+ *
39
+ * On first call, generates a 32-byte random value and persists it.
40
+ * On subsequent calls, reads the persisted value.
41
+ *
42
+ * @param baseDir - Optional base directory (default: ~/.yokotoken)
43
+ * @returns The install ID as a hex string
44
+ */
45
+ export function ensureInstallId(baseDir) {
46
+ const dir = baseDir ?? getDeviceDir();
47
+ const idPath = getInstallIdPath(dir);
48
+ if (existsSync(idPath)) {
49
+ return readFileSync(idPath, 'utf-8').trim();
50
+ }
51
+ // Create directory if needed
52
+ if (!existsSync(dir)) {
53
+ mkdirSync(dir, { recursive: true });
54
+ }
55
+ const installId = randomBytes(INSTALL_ID_BYTES).toString('hex');
56
+ writeFileSync(idPath, installId + '\n', 'utf-8');
57
+ return installId;
58
+ }
59
+ // ─── Machine Identity ──────────────────────────────────────────────
60
+ /**
61
+ * Collect machine identity components.
62
+ *
63
+ * Returns a deterministic string derived from the machine's hostname,
64
+ * OS platform, and current username. This provides a "best effort"
65
+ * machine identity that is stable across restarts.
66
+ *
67
+ * @returns A colon-separated identity string
68
+ */
69
+ export function getMachineIdentity() {
70
+ const host = hostname();
71
+ const os = platform();
72
+ let username;
73
+ try {
74
+ username = userInfo().username;
75
+ }
76
+ catch {
77
+ // userInfo() can throw on some systems (e.g., containers without /etc/passwd)
78
+ username = process.env.USER || process.env.USERNAME || 'unknown';
79
+ }
80
+ return `${host}:${os}:${username}`;
81
+ }
82
+ // ─── Fingerprint Generation ─────────────────────────────────────────
83
+ /**
84
+ * Generate a stable device fingerprint.
85
+ *
86
+ * The fingerprint is a SHA-256 hash of:
87
+ * machineIdentity + ":" + installId
88
+ *
89
+ * Properties:
90
+ * - Deterministic: same machine + same install-id = same fingerprint
91
+ * - Unique across machines: different hostname/OS/username = different hash
92
+ * - Unique across installs: different install-id = different hash (even on same machine)
93
+ * - Not reversible: SHA-256 hash cannot reveal machine details
94
+ *
95
+ * @param baseDir - Optional base directory for the install-id file (default: ~/.yokotoken)
96
+ * @returns A 64-character hex string (SHA-256 hash)
97
+ */
98
+ export function generateDeviceFingerprint(baseDir) {
99
+ const machineId = getMachineIdentity();
100
+ const installId = ensureInstallId(baseDir);
101
+ const input = `${machineId}:${installId}`;
102
+ return createHash('sha256').update(input).digest('hex');
103
+ }
104
+ /**
105
+ * Generate a user-friendly device name from system info.
106
+ *
107
+ * Format: "{username}@{hostname}" — human-readable but not guaranteed unique.
108
+ * Used as the default display name for a device in the known_devices registry.
109
+ *
110
+ * @returns A human-friendly device name string
111
+ */
112
+ export function getDefaultDeviceName() {
113
+ const host = hostname();
114
+ let username;
115
+ try {
116
+ username = userInfo().username;
117
+ }
118
+ catch {
119
+ username = process.env.USER || process.env.USERNAME || 'unknown';
120
+ }
121
+ return `${username}@${host}`;
122
+ }
123
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/signatures/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Device approval guard for unotoken.
3
+ *
4
+ * This module provides a guard that checks whether the current device is
5
+ * approved before allowing vault operations. It integrates:
6
+ * - Device fingerprinting (fingerprint.ts)
7
+ * - Known devices registry (devices.ts)
8
+ * - Email configuration (email-config.ts)
9
+ * - Approval codes (approval-codes.ts)
10
+ * - Email sending (resend.ts)
11
+ *
12
+ * The guard runs BEFORE vault unlock -- a new device cannot even attempt
13
+ * to unlock without approval.
14
+ *
15
+ * Usage patterns:
16
+ * 1. CLI (TTY): Prompts interactively for the 6-digit code
17
+ * 2. SDK (programmatic): Throws DeviceApprovalRequired with instructions
18
+ *
19
+ * Graceful degradation: If no email is configured, the guard allows the
20
+ * operation to proceed (signatures are opt-in via email config).
21
+ *
22
+ * @module
23
+ */
24
+ export interface DeviceGuardOptions {
25
+ /** Base directory for config/database files (default: ~/.yokotoken) */
26
+ baseDir?: string;
27
+ /** Whether running in a TTY context (can prompt user). Default: auto-detect from process.stdin */
28
+ isTTY?: boolean;
29
+ /** Function to read a line from the user (for TTY prompting). Injected for testability. */
30
+ readLine?: (prompt: string) => Promise<string>;
31
+ /** Function to write output (for TTY messaging). Injected for testability. */
32
+ writeOutput?: (message: string) => void;
33
+ /** Function to write error output. Injected for testability. */
34
+ writeError?: (message: string) => void;
35
+ }
36
+ export interface DeviceGuardResult {
37
+ /** Whether the operation should proceed */
38
+ allowed: boolean;
39
+ /** Whether the device was newly approved during this check */
40
+ newlyApproved: boolean;
41
+ /** Whether the device was auto-approved (first device, no email needed) */
42
+ autoApproved: boolean;
43
+ /** Device name (for display) */
44
+ deviceName: string;
45
+ /** Device fingerprint */
46
+ fingerprint: string;
47
+ /** Reason the operation was blocked (if allowed = false) */
48
+ reason?: string;
49
+ }
50
+ /**
51
+ * Error thrown when a device requires approval but is used programmatically
52
+ * (no TTY to prompt the user).
53
+ *
54
+ * The caller (app/cloud service) is responsible for:
55
+ * 1. Sending the code via approveDevice()
56
+ * 2. Collecting the code from the user
57
+ * 3. Calling completeApproval() with the code
58
+ */
59
+ export declare class DeviceApprovalRequired extends Error {
60
+ /** The device fingerprint that needs approval */
61
+ fingerprint: string;
62
+ /** The masked email where the code was sent (or null if not sent) */
63
+ maskedEmail: string | null;
64
+ /** Whether a code was actually sent */
65
+ codeSent: boolean;
66
+ constructor(fingerprint: string, maskedEmail: string | null, codeSent: boolean);
67
+ }
68
+ /**
69
+ * Check if the current device is approved and handle the approval flow.
70
+ *
71
+ * This is the main entry point for device checks. It should be called
72
+ * before any vault operation (unlock, get, set, list).
73
+ *
74
+ * Flow:
75
+ * 1. Generate device fingerprint
76
+ * 2. Check if device is known (auto-approves first device)
77
+ * 3. If known: allow operation, update last_seen
78
+ * 4. If unknown:
79
+ * a. If no email configured: allow (graceful degradation)
80
+ * b. If TTY: send code, prompt user, verify, register device
81
+ * c. If no TTY: throw DeviceApprovalRequired
82
+ *
83
+ * @param options - Guard configuration
84
+ * @returns Result indicating whether the operation should proceed
85
+ * @throws DeviceApprovalRequired when used programmatically and device is unknown
86
+ */
87
+ export declare function deviceGuard(options?: DeviceGuardOptions): Promise<DeviceGuardResult>;
88
+ /**
89
+ * Programmatically approve a device with an approval code.
90
+ *
91
+ * For use by SDK consumers who caught DeviceApprovalRequired and collected
92
+ * the code from the user via their own UI.
93
+ *
94
+ * @param fingerprint - The device fingerprint from the error
95
+ * @param code - The 6-digit code entered by the user
96
+ * @param baseDir - Optional base directory for config/database files
97
+ * @returns Object with `approved` boolean and optional `reason`
98
+ */
99
+ export declare function approveDevice(fingerprint: string, code: string, baseDir?: string): Promise<{
100
+ approved: boolean;
101
+ deviceName: string;
102
+ reason?: string;
103
+ }>;
104
+ /**
105
+ * Send an approval code to the user's configured email for a specific device.
106
+ *
107
+ * For use by SDK consumers who need to initiate the approval flow programmatically.
108
+ *
109
+ * @param fingerprint - The device fingerprint
110
+ * @param baseDir - Optional base directory for config/database files
111
+ * @returns Object with `sent` boolean, `maskedEmail`, and optional `error`
112
+ */
113
+ export declare function sendDeviceApprovalCode(fingerprint: string, baseDir?: string): Promise<{
114
+ sent: boolean;
115
+ maskedEmail?: string;
116
+ error?: string;
117
+ }>;
118
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/signatures/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAUH,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kGAAkG;IAClG,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,gEAAgE;IAChE,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,aAAa,EAAE,OAAO,CAAC;IACvB,2EAA2E;IAC3E,YAAY,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;gBAGhB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,EAAE,OAAO;CAcpB;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAwF5B;AAgJD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6ClE"}