@shin1ohno/sage 0.8.8 → 0.9.3
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.
- package/README.md +31 -0
- package/dist/cli/http-server-with-config.d.ts +2 -0
- package/dist/cli/http-server-with-config.d.ts.map +1 -1
- package/dist/cli/http-server-with-config.js +71 -0
- package/dist/cli/http-server-with-config.js.map +1 -1
- package/dist/cli/main-entry.d.ts.map +1 -1
- package/dist/cli/main-entry.js +1 -0
- package/dist/cli/main-entry.js.map +1 -1
- package/dist/cli/parser.d.ts +2 -0
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +7 -0
- package/dist/cli/parser.js.map +1 -1
- package/dist/config/validation.d.ts +721 -0
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +203 -0
- package/dist/config/validation.js.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/integrations/apple-reminders.d.ts.map +1 -1
- package/dist/integrations/apple-reminders.js +6 -5
- package/dist/integrations/apple-reminders.js.map +1 -1
- package/dist/integrations/calendar-event-creator.d.ts.map +1 -1
- package/dist/integrations/calendar-event-creator.js +2 -1
- package/dist/integrations/calendar-event-creator.js.map +1 -1
- package/dist/integrations/calendar-event-deleter.d.ts.map +1 -1
- package/dist/integrations/calendar-event-deleter.js +2 -1
- package/dist/integrations/calendar-event-deleter.js.map +1 -1
- package/dist/integrations/calendar-event-response.d.ts.map +1 -1
- package/dist/integrations/calendar-event-response.js +4 -3
- package/dist/integrations/calendar-event-response.js.map +1 -1
- package/dist/integrations/calendar-service.d.ts +14 -0
- package/dist/integrations/calendar-service.d.ts.map +1 -1
- package/dist/integrations/calendar-service.js +6 -5
- package/dist/integrations/calendar-service.js.map +1 -1
- package/dist/integrations/calendar-source-manager.d.ts +86 -3
- package/dist/integrations/calendar-source-manager.d.ts.map +1 -1
- package/dist/integrations/calendar-source-manager.js +152 -20
- package/dist/integrations/calendar-source-manager.js.map +1 -1
- package/dist/integrations/google-calendar-service.d.ts +55 -3
- package/dist/integrations/google-calendar-service.d.ts.map +1 -1
- package/dist/integrations/google-calendar-service.js +215 -5
- package/dist/integrations/google-calendar-service.js.map +1 -1
- package/dist/integrations/notion-mcp.d.ts.map +1 -1
- package/dist/integrations/notion-mcp.js +5 -4
- package/dist/integrations/notion-mcp.js.map +1 -1
- package/dist/integrations/todo-list-manager.d.ts.map +1 -1
- package/dist/integrations/todo-list-manager.js +3 -2
- package/dist/integrations/todo-list-manager.js.map +1 -1
- package/dist/oauth/encryption-service.d.ts +104 -0
- package/dist/oauth/encryption-service.d.ts.map +1 -0
- package/dist/oauth/encryption-service.js +271 -0
- package/dist/oauth/encryption-service.js.map +1 -0
- package/dist/oauth/file-mutex.d.ts +68 -0
- package/dist/oauth/file-mutex.d.ts.map +1 -0
- package/dist/oauth/file-mutex.js +141 -0
- package/dist/oauth/file-mutex.js.map +1 -0
- package/dist/oauth/google-oauth-handler.d.ts +8 -9
- package/dist/oauth/google-oauth-handler.d.ts.map +1 -1
- package/dist/oauth/google-oauth-handler.js +30 -65
- package/dist/oauth/google-oauth-handler.js.map +1 -1
- package/dist/oauth/index.d.ts +1 -0
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +2 -0
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/oauth-server.d.ts +61 -1
- package/dist/oauth/oauth-server.d.ts.map +1 -1
- package/dist/oauth/oauth-server.js +177 -40
- package/dist/oauth/oauth-server.js.map +1 -1
- package/dist/oauth/persistent-client-store.d.ts +58 -0
- package/dist/oauth/persistent-client-store.d.ts.map +1 -0
- package/dist/oauth/persistent-client-store.js +188 -0
- package/dist/oauth/persistent-client-store.js.map +1 -0
- package/dist/oauth/persistent-refresh-token-store.d.ts +77 -0
- package/dist/oauth/persistent-refresh-token-store.d.ts.map +1 -0
- package/dist/oauth/persistent-refresh-token-store.js +226 -0
- package/dist/oauth/persistent-refresh-token-store.js.map +1 -0
- package/dist/oauth/persistent-session-store.d.ts +69 -0
- package/dist/oauth/persistent-session-store.d.ts.map +1 -0
- package/dist/oauth/persistent-session-store.js +155 -0
- package/dist/oauth/persistent-session-store.js.map +1 -0
- package/dist/oauth/session-store.d.ts +31 -0
- package/dist/oauth/session-store.d.ts.map +1 -0
- package/dist/oauth/session-store.js +47 -0
- package/dist/oauth/session-store.js.map +1 -0
- package/dist/remote/cloud-config.d.ts.map +1 -1
- package/dist/remote/cloud-config.js +2 -1
- package/dist/remote/cloud-config.js.map +1 -1
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +3 -2
- package/dist/services/container.js.map +1 -1
- package/dist/services/working-cadence.d.ts +37 -1
- package/dist/services/working-cadence.d.ts.map +1 -1
- package/dist/services/working-cadence.js +152 -13
- package/dist/services/working-cadence.js.map +1 -1
- package/dist/tools/calendar/handlers.d.ts +82 -3
- package/dist/tools/calendar/handlers.d.ts.map +1 -1
- package/dist/tools/calendar/handlers.js +200 -16
- package/dist/tools/calendar/handlers.js.map +1 -1
- package/dist/types/google-calendar-types.d.ts +150 -3
- package/dist/types/google-calendar-types.d.ts.map +1 -1
- package/dist/types/google-calendar-types.js +79 -2
- package/dist/types/google-calendar-types.js.map +1 -1
- package/dist/types/task.d.ts +14 -0
- package/dist/types/task.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +28 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +61 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent Refresh Token Store
|
|
3
|
+
* Requirements: 21.6, 26.3, 26.8
|
|
4
|
+
*
|
|
5
|
+
* Extends InMemoryRefreshTokenStore with encrypted filesystem persistence.
|
|
6
|
+
* Maintains same interface but survives server restarts.
|
|
7
|
+
*/
|
|
8
|
+
import { RefreshTokenStore, RefreshTokenStoreConfig, GenerateRefreshTokenOptions, RefreshTokenValidationResult } from './refresh-token-store.js';
|
|
9
|
+
import { EncryptionService } from './encryption-service.js';
|
|
10
|
+
/**
|
|
11
|
+
* Persistent Refresh Token Store Implementation
|
|
12
|
+
*
|
|
13
|
+
* Provides encrypted filesystem persistence for refresh tokens
|
|
14
|
+
* while maintaining in-memory cache for fast access.
|
|
15
|
+
*/
|
|
16
|
+
export declare class PersistentRefreshTokenStore implements RefreshTokenStore {
|
|
17
|
+
private tokens;
|
|
18
|
+
private config;
|
|
19
|
+
private encryptionService;
|
|
20
|
+
private storagePath;
|
|
21
|
+
private saveDebounceTimer;
|
|
22
|
+
private saveDebounceMs;
|
|
23
|
+
constructor(config: RefreshTokenStoreConfig, encryptionService: EncryptionService, storagePath?: string);
|
|
24
|
+
/**
|
|
25
|
+
* Load tokens from encrypted file
|
|
26
|
+
*/
|
|
27
|
+
loadFromStorage(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Save tokens to encrypted file immediately
|
|
30
|
+
*/
|
|
31
|
+
saveToStorage(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Schedule save operation with debouncing
|
|
34
|
+
*
|
|
35
|
+
* Batches multiple writes within 1 second to reduce I/O operations.
|
|
36
|
+
*/
|
|
37
|
+
private scheduleSave;
|
|
38
|
+
/**
|
|
39
|
+
* Generate new refresh token
|
|
40
|
+
*/
|
|
41
|
+
generateToken(options: GenerateRefreshTokenOptions): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Validate refresh token
|
|
44
|
+
*/
|
|
45
|
+
validateToken(token: string, clientId: string): Promise<RefreshTokenValidationResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Rotate refresh token
|
|
48
|
+
*/
|
|
49
|
+
rotateToken(token: string, clientId: string): Promise<string | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Revoke refresh token
|
|
52
|
+
*/
|
|
53
|
+
revokeToken(token: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Revoke all tokens for client
|
|
56
|
+
*/
|
|
57
|
+
revokeAllForClient(clientId: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Clean up expired and rotated tokens
|
|
60
|
+
*/
|
|
61
|
+
cleanup(): Promise<number>;
|
|
62
|
+
/**
|
|
63
|
+
* Flush pending saves (call on server shutdown)
|
|
64
|
+
*
|
|
65
|
+
* Ensures all pending changes are written to disk before server shutdown.
|
|
66
|
+
*/
|
|
67
|
+
flush(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Get metrics for monitoring
|
|
70
|
+
*/
|
|
71
|
+
getMetrics(): {
|
|
72
|
+
count: number;
|
|
73
|
+
expiredCount: number;
|
|
74
|
+
rotatedCount: number;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=persistent-refresh-token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-refresh-token-store.d.ts","sourceRoot":"","sources":["../../src/oauth/persistent-refresh-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAW5D;;;;;GAKG;AACH,qBAAa,2BAA4B,YAAW,iBAAiB;IACnE,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,cAAc,CAAQ;gBAG5B,MAAM,EAAE,uBAAuB,EAC/B,iBAAiB,EAAE,iBAAiB,EACpC,WAAW,CAAC,EAAE,MAAM;IAOtB;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BtC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAUpC;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB1E;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,4BAA4B,CAAC;IA2B3F;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsB1E;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C;;OAEG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBhC;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACH,UAAU,IAAI;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB;CAoBF"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent Refresh Token Store
|
|
3
|
+
* Requirements: 21.6, 26.3, 26.8
|
|
4
|
+
*
|
|
5
|
+
* Extends InMemoryRefreshTokenStore with encrypted filesystem persistence.
|
|
6
|
+
* Maintains same interface but survives server restarts.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
import { randomBytes } from 'crypto';
|
|
11
|
+
import { oauthLogger } from '../utils/logger.js';
|
|
12
|
+
/**
|
|
13
|
+
* Persistent Refresh Token Store Implementation
|
|
14
|
+
*
|
|
15
|
+
* Provides encrypted filesystem persistence for refresh tokens
|
|
16
|
+
* while maintaining in-memory cache for fast access.
|
|
17
|
+
*/
|
|
18
|
+
export class PersistentRefreshTokenStore {
|
|
19
|
+
tokens = new Map();
|
|
20
|
+
config;
|
|
21
|
+
encryptionService;
|
|
22
|
+
storagePath;
|
|
23
|
+
saveDebounceTimer = null;
|
|
24
|
+
saveDebounceMs = 1000; // Batch saves within 1 second
|
|
25
|
+
constructor(config, encryptionService, storagePath) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.encryptionService = encryptionService;
|
|
28
|
+
this.storagePath = storagePath || join(homedir(), '.sage', 'oauth_refresh_tokens.enc');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Load tokens from encrypted file
|
|
32
|
+
*/
|
|
33
|
+
async loadFromStorage() {
|
|
34
|
+
const data = await this.encryptionService.decryptFromFile(this.storagePath);
|
|
35
|
+
if (!data) {
|
|
36
|
+
oauthLogger.info('No existing refresh tokens found, starting fresh');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const storage = JSON.parse(data);
|
|
41
|
+
// Load tokens and filter expired ones
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
let loadedCount = 0;
|
|
44
|
+
let expiredCount = 0;
|
|
45
|
+
for (const token of storage.tokens) {
|
|
46
|
+
if (now < token.expires_at) {
|
|
47
|
+
this.tokens.set(token.token, token);
|
|
48
|
+
loadedCount++;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
expiredCount++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
oauthLogger.info({ loadedCount, expiredCount }, 'Loaded refresh tokens');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
oauthLogger.error({ err: error }, 'Failed to parse refresh token storage, starting fresh');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Save tokens to encrypted file immediately
|
|
62
|
+
*/
|
|
63
|
+
async saveToStorage() {
|
|
64
|
+
const storage = {
|
|
65
|
+
version: 1,
|
|
66
|
+
tokens: Array.from(this.tokens.values()),
|
|
67
|
+
};
|
|
68
|
+
const data = JSON.stringify(storage, null, 2);
|
|
69
|
+
await this.encryptionService.encryptToFile(data, this.storagePath);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Schedule save operation with debouncing
|
|
73
|
+
*
|
|
74
|
+
* Batches multiple writes within 1 second to reduce I/O operations.
|
|
75
|
+
*/
|
|
76
|
+
scheduleSave() {
|
|
77
|
+
// Clear existing timer
|
|
78
|
+
if (this.saveDebounceTimer) {
|
|
79
|
+
clearTimeout(this.saveDebounceTimer);
|
|
80
|
+
}
|
|
81
|
+
// Schedule save after debounce period
|
|
82
|
+
this.saveDebounceTimer = setTimeout(async () => {
|
|
83
|
+
try {
|
|
84
|
+
await this.saveToStorage();
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
oauthLogger.error({ err: error }, 'Failed to save refresh tokens');
|
|
88
|
+
}
|
|
89
|
+
}, this.saveDebounceMs);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate new refresh token
|
|
93
|
+
*/
|
|
94
|
+
async generateToken(options) {
|
|
95
|
+
// Generate secure random token
|
|
96
|
+
const token = randomBytes(32).toString('base64url');
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const expiresAt = now + this.config.expirySeconds * 1000;
|
|
99
|
+
const tokenData = {
|
|
100
|
+
token,
|
|
101
|
+
client_id: options.clientId,
|
|
102
|
+
user_id: options.userId,
|
|
103
|
+
scope: options.scope,
|
|
104
|
+
created_at: now,
|
|
105
|
+
expires_at: expiresAt,
|
|
106
|
+
rotated: false,
|
|
107
|
+
};
|
|
108
|
+
this.tokens.set(token, tokenData);
|
|
109
|
+
// Schedule debounced save
|
|
110
|
+
this.scheduleSave();
|
|
111
|
+
return token;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Validate refresh token
|
|
115
|
+
*/
|
|
116
|
+
async validateToken(token, clientId) {
|
|
117
|
+
const tokenData = this.tokens.get(token);
|
|
118
|
+
if (!tokenData) {
|
|
119
|
+
return { valid: false, error: 'invalid_grant' };
|
|
120
|
+
}
|
|
121
|
+
// Check if token has been rotated
|
|
122
|
+
if (tokenData.rotated) {
|
|
123
|
+
return { valid: false, error: 'invalid_grant' };
|
|
124
|
+
}
|
|
125
|
+
// Check if token has expired
|
|
126
|
+
if (Date.now() > tokenData.expires_at) {
|
|
127
|
+
this.tokens.delete(token);
|
|
128
|
+
this.scheduleSave();
|
|
129
|
+
return { valid: false, error: 'invalid_grant' };
|
|
130
|
+
}
|
|
131
|
+
// Verify client_id matches
|
|
132
|
+
if (tokenData.client_id !== clientId) {
|
|
133
|
+
return { valid: false, error: 'invalid_grant' };
|
|
134
|
+
}
|
|
135
|
+
return { valid: true, tokenData };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Rotate refresh token
|
|
139
|
+
*/
|
|
140
|
+
async rotateToken(token, clientId) {
|
|
141
|
+
const validationResult = await this.validateToken(token, clientId);
|
|
142
|
+
if (!validationResult.valid || !validationResult.tokenData) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
// Mark old token as rotated (Requirement 26.8)
|
|
146
|
+
const oldTokenData = this.tokens.get(token);
|
|
147
|
+
oldTokenData.rotated = true;
|
|
148
|
+
// Generate new token with same scope
|
|
149
|
+
const newToken = await this.generateToken({
|
|
150
|
+
clientId: validationResult.tokenData.client_id,
|
|
151
|
+
userId: validationResult.tokenData.user_id,
|
|
152
|
+
scope: validationResult.tokenData.scope,
|
|
153
|
+
});
|
|
154
|
+
// scheduleSave is already called in generateToken
|
|
155
|
+
return newToken;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Revoke refresh token
|
|
159
|
+
*/
|
|
160
|
+
async revokeToken(token) {
|
|
161
|
+
this.tokens.delete(token);
|
|
162
|
+
this.scheduleSave();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Revoke all tokens for client
|
|
166
|
+
*/
|
|
167
|
+
async revokeAllForClient(clientId) {
|
|
168
|
+
for (const [token, data] of this.tokens.entries()) {
|
|
169
|
+
if (data.client_id === clientId) {
|
|
170
|
+
this.tokens.delete(token);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
this.scheduleSave();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clean up expired and rotated tokens
|
|
177
|
+
*/
|
|
178
|
+
async cleanup() {
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
let cleanedCount = 0;
|
|
181
|
+
for (const [token, data] of this.tokens.entries()) {
|
|
182
|
+
if (data.expires_at < now || data.rotated) {
|
|
183
|
+
this.tokens.delete(token);
|
|
184
|
+
cleanedCount++;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (cleanedCount > 0) {
|
|
188
|
+
this.scheduleSave();
|
|
189
|
+
}
|
|
190
|
+
return cleanedCount;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Flush pending saves (call on server shutdown)
|
|
194
|
+
*
|
|
195
|
+
* Ensures all pending changes are written to disk before server shutdown.
|
|
196
|
+
*/
|
|
197
|
+
async flush() {
|
|
198
|
+
if (this.saveDebounceTimer) {
|
|
199
|
+
clearTimeout(this.saveDebounceTimer);
|
|
200
|
+
this.saveDebounceTimer = null;
|
|
201
|
+
}
|
|
202
|
+
await this.saveToStorage();
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get metrics for monitoring
|
|
206
|
+
*/
|
|
207
|
+
getMetrics() {
|
|
208
|
+
const now = Date.now();
|
|
209
|
+
let expiredCount = 0;
|
|
210
|
+
let rotatedCount = 0;
|
|
211
|
+
for (const token of this.tokens.values()) {
|
|
212
|
+
if (token.expires_at < now) {
|
|
213
|
+
expiredCount++;
|
|
214
|
+
}
|
|
215
|
+
if (token.rotated) {
|
|
216
|
+
rotatedCount++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
count: this.tokens.size,
|
|
221
|
+
expiredCount,
|
|
222
|
+
rotatedCount,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=persistent-refresh-token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-refresh-token-store.js","sourceRoot":"","sources":["../../src/oauth/persistent-refresh-token-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent Session Store
|
|
3
|
+
* Requirements: 26 (Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Stores user sessions with encrypted filesystem persistence.
|
|
6
|
+
* Implements automatic cleanup of expired sessions and session limits.
|
|
7
|
+
*/
|
|
8
|
+
import { UserSession } from './types.js';
|
|
9
|
+
import { EncryptionService } from './encryption-service.js';
|
|
10
|
+
import { SessionStore } from './session-store.js';
|
|
11
|
+
/**
|
|
12
|
+
* Persistent Session Store Implementation
|
|
13
|
+
*
|
|
14
|
+
* Extends SessionStore interface with encrypted filesystem persistence.
|
|
15
|
+
* Maintains in-memory cache for fast access while persisting to disk.
|
|
16
|
+
*/
|
|
17
|
+
export declare class PersistentSessionStore implements SessionStore {
|
|
18
|
+
private sessions;
|
|
19
|
+
private sessionExpiryMs;
|
|
20
|
+
private maxSessions;
|
|
21
|
+
private encryptionService;
|
|
22
|
+
private storagePath;
|
|
23
|
+
constructor(encryptionService: EncryptionService, storagePath?: string);
|
|
24
|
+
/**
|
|
25
|
+
* Load sessions from encrypted file
|
|
26
|
+
*
|
|
27
|
+
* Filters out expired sessions during load.
|
|
28
|
+
* Logs loaded and expired session counts.
|
|
29
|
+
*/
|
|
30
|
+
loadFromStorage(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Save sessions to encrypted file
|
|
33
|
+
*
|
|
34
|
+
* Enforces session limit by keeping only most recent 100 sessions.
|
|
35
|
+
*/
|
|
36
|
+
private saveToStorage;
|
|
37
|
+
/**
|
|
38
|
+
* Create new session
|
|
39
|
+
*
|
|
40
|
+
* Saves asynchronously (fire and forget) to avoid blocking.
|
|
41
|
+
*/
|
|
42
|
+
createSession(userId: string): UserSession;
|
|
43
|
+
/**
|
|
44
|
+
* Get session by ID
|
|
45
|
+
*
|
|
46
|
+
* Checks expiry and removes expired sessions automatically.
|
|
47
|
+
*/
|
|
48
|
+
getSession(sessionId: string): UserSession | null;
|
|
49
|
+
/**
|
|
50
|
+
* Delete session
|
|
51
|
+
*
|
|
52
|
+
* Saves asynchronously after deletion.
|
|
53
|
+
*/
|
|
54
|
+
deleteSession(sessionId: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Flush pending saves
|
|
57
|
+
*
|
|
58
|
+
* Call on server shutdown to ensure all data is persisted.
|
|
59
|
+
*/
|
|
60
|
+
flush(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Get metrics for monitoring
|
|
63
|
+
*/
|
|
64
|
+
getMetrics(): {
|
|
65
|
+
count: number;
|
|
66
|
+
expiredCount: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=persistent-session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-session-store.d.ts","sourceRoot":"","sources":["../../src/oauth/persistent-session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWlD;;;;;GAKG;AACH,qBAAa,sBAAuB,YAAW,YAAY;IACzD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAS;gBAEhB,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,CAAC,EAAE,MAAM;IAKtE;;;;;OAKG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BtC;;;;OAIG;YACW,aAAa;IAuB3B;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAmB1C;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAgBjD;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOtC;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,UAAU,IAAI;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;KACtB;CAeF"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent Session Store
|
|
3
|
+
* Requirements: 26 (Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Stores user sessions with encrypted filesystem persistence.
|
|
6
|
+
* Implements automatic cleanup of expired sessions and session limits.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
import { randomBytes } from 'crypto';
|
|
11
|
+
import { oauthLogger } from '../utils/logger.js';
|
|
12
|
+
/**
|
|
13
|
+
* Persistent Session Store Implementation
|
|
14
|
+
*
|
|
15
|
+
* Extends SessionStore interface with encrypted filesystem persistence.
|
|
16
|
+
* Maintains in-memory cache for fast access while persisting to disk.
|
|
17
|
+
*/
|
|
18
|
+
export class PersistentSessionStore {
|
|
19
|
+
sessions = new Map();
|
|
20
|
+
sessionExpiryMs = 24 * 60 * 60 * 1000; // 24 hours
|
|
21
|
+
maxSessions = 100; // Limit to prevent unbounded growth
|
|
22
|
+
encryptionService;
|
|
23
|
+
storagePath;
|
|
24
|
+
constructor(encryptionService, storagePath) {
|
|
25
|
+
this.encryptionService = encryptionService;
|
|
26
|
+
this.storagePath = storagePath || join(homedir(), '.sage', 'oauth_sessions.enc');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Load sessions from encrypted file
|
|
30
|
+
*
|
|
31
|
+
* Filters out expired sessions during load.
|
|
32
|
+
* Logs loaded and expired session counts.
|
|
33
|
+
*/
|
|
34
|
+
async loadFromStorage() {
|
|
35
|
+
const data = await this.encryptionService.decryptFromFile(this.storagePath);
|
|
36
|
+
if (!data) {
|
|
37
|
+
oauthLogger.info('No existing sessions found, starting fresh');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const storage = JSON.parse(data);
|
|
42
|
+
// Load sessions and filter expired ones
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
let loadedCount = 0;
|
|
45
|
+
let expiredCount = 0;
|
|
46
|
+
for (const session of storage.sessions) {
|
|
47
|
+
if (now < session.expiresAt) {
|
|
48
|
+
this.sessions.set(session.sessionId, session);
|
|
49
|
+
loadedCount++;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
expiredCount++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
oauthLogger.info({ loadedCount, expiredCount }, 'Loaded sessions');
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
oauthLogger.error({ err: error }, 'Failed to parse session storage, starting fresh');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Save sessions to encrypted file
|
|
63
|
+
*
|
|
64
|
+
* Enforces session limit by keeping only most recent 100 sessions.
|
|
65
|
+
*/
|
|
66
|
+
async saveToStorage() {
|
|
67
|
+
// Enforce session limit by keeping only most recent sessions
|
|
68
|
+
let sessions = Array.from(this.sessions.values());
|
|
69
|
+
if (sessions.length > this.maxSessions) {
|
|
70
|
+
sessions.sort((a, b) => b.createdAt - a.createdAt);
|
|
71
|
+
sessions = sessions.slice(0, this.maxSessions);
|
|
72
|
+
// Update map to reflect limit
|
|
73
|
+
this.sessions.clear();
|
|
74
|
+
for (const session of sessions) {
|
|
75
|
+
this.sessions.set(session.sessionId, session);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const storage = {
|
|
79
|
+
version: 1,
|
|
80
|
+
sessions,
|
|
81
|
+
};
|
|
82
|
+
const data = JSON.stringify(storage, null, 2);
|
|
83
|
+
await this.encryptionService.encryptToFile(data, this.storagePath);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create new session
|
|
87
|
+
*
|
|
88
|
+
* Saves asynchronously (fire and forget) to avoid blocking.
|
|
89
|
+
*/
|
|
90
|
+
createSession(userId) {
|
|
91
|
+
const sessionId = randomBytes(32).toString('hex');
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const session = {
|
|
94
|
+
sessionId,
|
|
95
|
+
userId,
|
|
96
|
+
createdAt: now,
|
|
97
|
+
expiresAt: now + this.sessionExpiryMs,
|
|
98
|
+
};
|
|
99
|
+
this.sessions.set(sessionId, session);
|
|
100
|
+
// Save asynchronously (don't wait)
|
|
101
|
+
this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save session'));
|
|
102
|
+
return session;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get session by ID
|
|
106
|
+
*
|
|
107
|
+
* Checks expiry and removes expired sessions automatically.
|
|
108
|
+
*/
|
|
109
|
+
getSession(sessionId) {
|
|
110
|
+
const session = this.sessions.get(sessionId);
|
|
111
|
+
if (!session)
|
|
112
|
+
return null;
|
|
113
|
+
// Check expiry
|
|
114
|
+
if (Date.now() > session.expiresAt) {
|
|
115
|
+
this.sessions.delete(sessionId);
|
|
116
|
+
this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save after session expiry'));
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return session;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Delete session
|
|
123
|
+
*
|
|
124
|
+
* Saves asynchronously after deletion.
|
|
125
|
+
*/
|
|
126
|
+
deleteSession(sessionId) {
|
|
127
|
+
this.sessions.delete(sessionId);
|
|
128
|
+
this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save after session deletion'));
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Flush pending saves
|
|
132
|
+
*
|
|
133
|
+
* Call on server shutdown to ensure all data is persisted.
|
|
134
|
+
*/
|
|
135
|
+
async flush() {
|
|
136
|
+
await this.saveToStorage();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get metrics for monitoring
|
|
140
|
+
*/
|
|
141
|
+
getMetrics() {
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
let expiredCount = 0;
|
|
144
|
+
for (const session of this.sessions.values()) {
|
|
145
|
+
if (session.expiresAt < now) {
|
|
146
|
+
expiredCount++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
count: this.sessions.size,
|
|
151
|
+
expiredCount,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=persistent-session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-session-store.js","sourceRoot":"","sources":["../../src/oauth/persistent-session-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Store
|
|
3
|
+
* Requirements: 26 (Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Manages user sessions for OAuth authentication flow.
|
|
6
|
+
* Sessions track authenticated users during the consent process.
|
|
7
|
+
*/
|
|
8
|
+
import { UserSession } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Session Store Interface
|
|
11
|
+
*/
|
|
12
|
+
export interface SessionStore {
|
|
13
|
+
createSession(userId: string): UserSession;
|
|
14
|
+
getSession(sessionId: string): UserSession | null;
|
|
15
|
+
deleteSession(sessionId: string): void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* In-memory Session Store Implementation
|
|
19
|
+
*/
|
|
20
|
+
export declare class InMemorySessionStore implements SessionStore {
|
|
21
|
+
private sessions;
|
|
22
|
+
private sessionExpiryMs;
|
|
23
|
+
createSession(userId: string): UserSession;
|
|
24
|
+
getSession(sessionId: string): UserSession | null;
|
|
25
|
+
deleteSession(sessionId: string): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a Session Store instance
|
|
29
|
+
*/
|
|
30
|
+
export declare function createSessionStore(): SessionStore;
|
|
31
|
+
//# sourceMappingURL=session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/oauth/session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAClD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,eAAe,CAAuB;IAE9C,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAa1C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAUjD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAGvC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Store
|
|
3
|
+
* Requirements: 26 (Session Management)
|
|
4
|
+
*
|
|
5
|
+
* Manages user sessions for OAuth authentication flow.
|
|
6
|
+
* Sessions track authenticated users during the consent process.
|
|
7
|
+
*/
|
|
8
|
+
import { randomBytes } from 'crypto';
|
|
9
|
+
/**
|
|
10
|
+
* In-memory Session Store Implementation
|
|
11
|
+
*/
|
|
12
|
+
export class InMemorySessionStore {
|
|
13
|
+
sessions = new Map();
|
|
14
|
+
sessionExpiryMs = 24 * 60 * 60 * 1000; // 24 hours
|
|
15
|
+
createSession(userId) {
|
|
16
|
+
const sessionId = randomBytes(32).toString('hex');
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
const session = {
|
|
19
|
+
sessionId,
|
|
20
|
+
userId,
|
|
21
|
+
createdAt: now,
|
|
22
|
+
expiresAt: now + this.sessionExpiryMs,
|
|
23
|
+
};
|
|
24
|
+
this.sessions.set(sessionId, session);
|
|
25
|
+
return session;
|
|
26
|
+
}
|
|
27
|
+
getSession(sessionId) {
|
|
28
|
+
const session = this.sessions.get(sessionId);
|
|
29
|
+
if (!session)
|
|
30
|
+
return null;
|
|
31
|
+
if (Date.now() > session.expiresAt) {
|
|
32
|
+
this.sessions.delete(sessionId);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return session;
|
|
36
|
+
}
|
|
37
|
+
deleteSession(sessionId) {
|
|
38
|
+
this.sessions.delete(sessionId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a Session Store instance
|
|
43
|
+
*/
|
|
44
|
+
export function createSessionStore() {
|
|
45
|
+
return new InMemorySessionStore();
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/oauth/session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAYrC;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACvB,QAAQ,GAA6B,IAAI,GAAG,EAAE,CAAC;IAC/C,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;IAE1D,aAAa,CAAC,MAAc;QAC1B,MAAM,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,MAAM;YACN,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,eAAe;SACtC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,oBAAoB,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../../src/remote/cloud-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../../src/remote/cloud-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Requirements: 12.3, 12.6
|
|
5
5
|
*/
|
|
6
6
|
import { createCipheriv, createDecipheriv, randomBytes, createHash } from 'crypto';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
7
8
|
/**
|
|
8
9
|
* Cloud Configuration Manager
|
|
9
10
|
* Handles encrypted cloud sync of configurations
|
|
@@ -221,7 +222,7 @@ export class CloudConfigManager {
|
|
|
221
222
|
return this.localConfig;
|
|
222
223
|
}
|
|
223
224
|
catch (error) {
|
|
224
|
-
|
|
225
|
+
logger.error({ err: error }, 'Failed to sync from cloud');
|
|
225
226
|
return null;
|
|
226
227
|
}
|
|
227
228
|
}
|