@itphx/synth-core 0.3.0 → 0.4.4
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/dist/auth/local.d.ts +14 -0
- package/dist/auth/local.d.ts.map +1 -1
- package/dist/auth/local.js +63 -11
- package/dist/auth/local.js.map +1 -1
- package/dist/auth/local.test.js +59 -0
- package/dist/auth/local.test.js.map +1 -1
- package/dist/events/bus.d.ts +7 -0
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/bus.js +26 -3
- package/dist/events/bus.js.map +1 -1
- package/dist/events/bus.test.js +46 -0
- package/dist/events/bus.test.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main.js +247 -8
- package/dist/main.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/remote.d.ts +60 -0
- package/dist/providers/remote.d.ts.map +1 -0
- package/dist/providers/remote.js +394 -0
- package/dist/providers/remote.js.map +1 -0
- package/dist/providers/remote.test.d.ts +2 -0
- package/dist/providers/remote.test.d.ts.map +1 -0
- package/dist/providers/remote.test.js +258 -0
- package/dist/providers/remote.test.js.map +1 -0
- package/dist/remote/aggregate.d.ts +43 -0
- package/dist/remote/aggregate.d.ts.map +1 -0
- package/dist/remote/aggregate.js +84 -0
- package/dist/remote/aggregate.js.map +1 -0
- package/dist/remote/aggregate.test.d.ts +2 -0
- package/dist/remote/aggregate.test.d.ts.map +1 -0
- package/dist/remote/aggregate.test.js +120 -0
- package/dist/remote/aggregate.test.js.map +1 -0
- package/dist/remote/client.d.ts +142 -0
- package/dist/remote/client.d.ts.map +1 -0
- package/dist/remote/client.js +290 -0
- package/dist/remote/client.js.map +1 -0
- package/dist/remote/client.test.d.ts +2 -0
- package/dist/remote/client.test.d.ts.map +1 -0
- package/dist/remote/client.test.js +176 -0
- package/dist/remote/client.test.js.map +1 -0
- package/dist/remote/connection.d.ts +66 -0
- package/dist/remote/connection.d.ts.map +1 -0
- package/dist/remote/connection.js +298 -0
- package/dist/remote/connection.js.map +1 -0
- package/dist/remote/connection.test.d.ts +2 -0
- package/dist/remote/connection.test.d.ts.map +1 -0
- package/dist/remote/connection.test.js +323 -0
- package/dist/remote/connection.test.js.map +1 -0
- package/dist/remote/credentials.d.ts +13 -0
- package/dist/remote/credentials.d.ts.map +1 -0
- package/dist/remote/credentials.js +81 -0
- package/dist/remote/credentials.js.map +1 -0
- package/dist/remote/credentials.test.d.ts +2 -0
- package/dist/remote/credentials.test.d.ts.map +1 -0
- package/dist/remote/credentials.test.js +69 -0
- package/dist/remote/credentials.test.js.map +1 -0
- package/dist/remote/device-flow.d.ts +72 -0
- package/dist/remote/device-flow.d.ts.map +1 -0
- package/dist/remote/device-flow.js +229 -0
- package/dist/remote/device-flow.js.map +1 -0
- package/dist/remote/device-flow.test.d.ts +2 -0
- package/dist/remote/device-flow.test.d.ts.map +1 -0
- package/dist/remote/device-flow.test.js +103 -0
- package/dist/remote/device-flow.test.js.map +1 -0
- package/dist/remote/event-bridge.d.ts +46 -0
- package/dist/remote/event-bridge.d.ts.map +1 -0
- package/dist/remote/event-bridge.js +218 -0
- package/dist/remote/event-bridge.js.map +1 -0
- package/dist/remote/event-bridge.test.d.ts +2 -0
- package/dist/remote/event-bridge.test.d.ts.map +1 -0
- package/dist/remote/event-bridge.test.js +240 -0
- package/dist/remote/event-bridge.test.js.map +1 -0
- package/dist/remote/index.d.ts +19 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +11 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/remote/session.d.ts +72 -0
- package/dist/remote/session.d.ts.map +1 -0
- package/dist/remote/session.js +248 -0
- package/dist/remote/session.js.map +1 -0
- package/dist/remote/session.test.d.ts +2 -0
- package/dist/remote/session.test.d.ts.map +1 -0
- package/dist/remote/session.test.js +482 -0
- package/dist/remote/session.test.js.map +1 -0
- package/dist/remote/transfer.d.ts +75 -0
- package/dist/remote/transfer.d.ts.map +1 -0
- package/dist/remote/transfer.js +491 -0
- package/dist/remote/transfer.js.map +1 -0
- package/dist/remote/transfer.test.d.ts +2 -0
- package/dist/remote/transfer.test.d.ts.map +1 -0
- package/dist/remote/transfer.test.js +416 -0
- package/dist/remote/transfer.test.js.map +1 -0
- package/dist/remote/types.d.ts +28 -0
- package/dist/remote/types.d.ts.map +1 -0
- package/dist/remote/types.js +10 -0
- package/dist/remote/types.js.map +1 -0
- package/dist/server/app.d.ts +62 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +364 -20
- package/dist/server/app.js.map +1 -1
- package/dist/server/app.proxy.test.d.ts +2 -0
- package/dist/server/app.proxy.test.d.ts.map +1 -0
- package/dist/server/app.proxy.test.js +193 -0
- package/dist/server/app.proxy.test.js.map +1 -0
- package/dist/server/app.remote.test.d.ts +2 -0
- package/dist/server/app.remote.test.d.ts.map +1 -0
- package/dist/server/app.remote.test.js +674 -0
- package/dist/server/app.remote.test.js.map +1 -0
- package/dist/server/proxy.d.ts +14 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +93 -0
- package/dist/server/proxy.js.map +1 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.d.ts.map +1 -1
- package/dist/server/routes/auth.js +269 -36
- package/dist/server/routes/auth.js.map +1 -1
- package/dist/server/routes/auth.test.d.ts +2 -0
- package/dist/server/routes/auth.test.d.ts.map +1 -0
- package/dist/server/routes/auth.test.js +466 -0
- package/dist/server/routes/auth.test.js.map +1 -0
- package/dist/server/routes/fs.d.ts +2 -1
- package/dist/server/routes/fs.d.ts.map +1 -1
- package/dist/server/routes/fs.js +159 -5
- package/dist/server/routes/fs.js.map +1 -1
- package/dist/server/routes/hybrid.d.ts +32 -0
- package/dist/server/routes/hybrid.d.ts.map +1 -0
- package/dist/server/routes/hybrid.js +21 -0
- package/dist/server/routes/hybrid.js.map +1 -0
- package/dist/server/routes/hybrid.test.d.ts +2 -0
- package/dist/server/routes/hybrid.test.d.ts.map +1 -0
- package/dist/server/routes/hybrid.test.js +454 -0
- package/dist/server/routes/hybrid.test.js.map +1 -0
- package/dist/server/routes/messages.d.ts +2 -1
- package/dist/server/routes/messages.d.ts.map +1 -1
- package/dist/server/routes/messages.js +104 -1
- package/dist/server/routes/messages.js.map +1 -1
- package/dist/server/routes/models.cache.test.d.ts +2 -0
- package/dist/server/routes/models.cache.test.d.ts.map +1 -0
- package/dist/server/routes/models.cache.test.js +59 -0
- package/dist/server/routes/models.cache.test.js.map +1 -0
- package/dist/server/routes/models.d.ts +9 -1
- package/dist/server/routes/models.d.ts.map +1 -1
- package/dist/server/routes/models.js +35 -2
- package/dist/server/routes/models.js.map +1 -1
- package/dist/server/routes/models.remote.test.d.ts +2 -0
- package/dist/server/routes/models.remote.test.d.ts.map +1 -0
- package/dist/server/routes/models.remote.test.js +101 -0
- package/dist/server/routes/models.remote.test.js.map +1 -0
- package/dist/server/routes/project-transfer.d.ts +16 -0
- package/dist/server/routes/project-transfer.d.ts.map +1 -0
- package/dist/server/routes/project-transfer.js +141 -0
- package/dist/server/routes/project-transfer.js.map +1 -0
- package/dist/server/routes/project-transfer.test.d.ts +2 -0
- package/dist/server/routes/project-transfer.test.d.ts.map +1 -0
- package/dist/server/routes/project-transfer.test.js +199 -0
- package/dist/server/routes/project-transfer.test.js.map +1 -0
- package/dist/server/routes/projects.d.ts +2 -1
- package/dist/server/routes/projects.d.ts.map +1 -1
- package/dist/server/routes/projects.js +101 -5
- package/dist/server/routes/projects.js.map +1 -1
- package/dist/server/routes/providers.d.ts +1 -1
- package/dist/server/routes/providers.d.ts.map +1 -1
- package/dist/server/routes/providers.js +3 -1
- package/dist/server/routes/providers.js.map +1 -1
- package/dist/server/routes/providers.test.d.ts +2 -0
- package/dist/server/routes/providers.test.d.ts.map +1 -0
- package/dist/server/routes/providers.test.js +58 -0
- package/dist/server/routes/providers.test.js.map +1 -0
- package/dist/server/routes/queue.d.ts +2 -1
- package/dist/server/routes/queue.d.ts.map +1 -1
- package/dist/server/routes/queue.js +89 -1
- package/dist/server/routes/queue.js.map +1 -1
- package/dist/server/routes/sessions.d.ts +8 -1
- package/dist/server/routes/sessions.d.ts.map +1 -1
- package/dist/server/routes/sessions.js +202 -9
- package/dist/server/routes/sessions.js.map +1 -1
- package/dist/server/serialize.d.ts +2 -0
- package/dist/server/serialize.d.ts.map +1 -1
- package/dist/server/serialize.js +2 -0
- package/dist/server/serialize.js.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { RemoteConnection } from './connection.js';
|
|
6
|
+
import { saveCredentials, loadCredentials } from './credentials.js';
|
|
7
|
+
import { RemoteError } from './types.js';
|
|
8
|
+
function jsonResponse(data, status = 200) {
|
|
9
|
+
return new Response(JSON.stringify(data), {
|
|
10
|
+
status,
|
|
11
|
+
headers: { 'Content-Type': 'application/json' },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const BACKEND = 'https://backend.test';
|
|
15
|
+
const ISSUER = 'https://kc.test/realms/synth';
|
|
16
|
+
const CLIENT_ID = 'synth-cli';
|
|
17
|
+
const OIDC_DISCOVERY = {
|
|
18
|
+
issuer: ISSUER,
|
|
19
|
+
token_endpoint: `${ISSUER}/protocol/openid-connect/token`,
|
|
20
|
+
device_authorization_endpoint: `${ISSUER}/protocol/openid-connect/auth/device`,
|
|
21
|
+
};
|
|
22
|
+
const SERVER_USER = { id: 'u-1', username: 'lucky', roles: ['ADMIN', 'USER'] };
|
|
23
|
+
/**
|
|
24
|
+
* fetch-мок успешного ROPC-входа: дискавери OIDC-меты на backend, token-грант
|
|
25
|
+
* (grant_type=password) на Keycloak, /auth/status с серверным пользователем.
|
|
26
|
+
*/
|
|
27
|
+
function passwordFlowFetchMock(overrides = {}) {
|
|
28
|
+
const { tokenStatus = 200, tokenBody } = overrides;
|
|
29
|
+
return vi.fn((url) => {
|
|
30
|
+
const u = String(url);
|
|
31
|
+
if (u.includes('/auth/oidc-meta')) {
|
|
32
|
+
return Promise.resolve(jsonResponse({ enabled: true, issuer: ISSUER, clientId: CLIENT_ID }));
|
|
33
|
+
}
|
|
34
|
+
if (u.includes('/protocol/openid-connect/token')) {
|
|
35
|
+
if (tokenStatus !== 200) {
|
|
36
|
+
return Promise.resolve(jsonResponse(tokenBody ?? { error: 'invalid_grant' }, tokenStatus));
|
|
37
|
+
}
|
|
38
|
+
return Promise.resolve(jsonResponse(tokenBody ?? {
|
|
39
|
+
access_token: 'at-ropc',
|
|
40
|
+
refresh_token: 'rt-ropc',
|
|
41
|
+
expires_in: 300,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
if (u.includes('/auth/status')) {
|
|
45
|
+
return Promise.resolve(jsonResponse({ authenticated: true, oidc_enabled: true, user: SERVER_USER }));
|
|
46
|
+
}
|
|
47
|
+
return Promise.resolve(jsonResponse({ error: 'not_found' }, 404));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** fetch-мок для connectFromSaved по протухшим credentials: oidc-meta + refresh-грант + status. */
|
|
51
|
+
function refreshFlowFetchMock() {
|
|
52
|
+
return vi.fn((url, init) => {
|
|
53
|
+
const u = String(url);
|
|
54
|
+
if (u.includes('/auth/oidc-meta')) {
|
|
55
|
+
return Promise.resolve(jsonResponse({ enabled: true, issuer: ISSUER, clientId: CLIENT_ID }));
|
|
56
|
+
}
|
|
57
|
+
if (u.includes('.well-known/openid-configuration')) {
|
|
58
|
+
return Promise.resolve(jsonResponse(OIDC_DISCOVERY));
|
|
59
|
+
}
|
|
60
|
+
if (u.includes('/protocol/openid-connect/token')) {
|
|
61
|
+
const body = init?.body instanceof URLSearchParams ? init.body : null;
|
|
62
|
+
if (body?.get('grant_type') === 'refresh_token') {
|
|
63
|
+
return Promise.resolve(jsonResponse({
|
|
64
|
+
access_token: 'at-refreshed',
|
|
65
|
+
refresh_token: 'rt-refreshed',
|
|
66
|
+
expires_in: 3600,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (u.includes('/auth/status')) {
|
|
71
|
+
return Promise.resolve(jsonResponse({ authenticated: true, oidc_enabled: true, user: SERVER_USER }));
|
|
72
|
+
}
|
|
73
|
+
return Promise.resolve(jsonResponse({ error: 'not_found' }, 404));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
vi.unstubAllGlobals();
|
|
78
|
+
});
|
|
79
|
+
describe('RemoteConnection.discoverOidc', () => {
|
|
80
|
+
it('сервер вернул {enabled:true, issuer, clientId} → возвращает их; адрес без завершающего /', async () => {
|
|
81
|
+
const fetchMock = vi.fn().mockResolvedValue(jsonResponse({ enabled: true, issuer: ISSUER, clientId: CLIENT_ID }));
|
|
82
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
83
|
+
const conn = new RemoteConnection({});
|
|
84
|
+
const meta = await conn.discoverOidc('https://backend.test/');
|
|
85
|
+
expect(meta).toEqual({ issuer: ISSUER, clientId: CLIENT_ID });
|
|
86
|
+
expect(fetchMock).toHaveBeenCalledWith('https://backend.test/auth/oidc-meta', expect.objectContaining({ signal: expect.anything() }));
|
|
87
|
+
});
|
|
88
|
+
it('enabled:false → RemoteError(AUTH) с русским сообщением', async () => {
|
|
89
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonResponse({ enabled: false })));
|
|
90
|
+
const conn = new RemoteConnection({ defaultIssuer: ISSUER, defaultClientId: CLIENT_ID });
|
|
91
|
+
const err = await conn.discoverOidc(BACKEND).catch((e) => e);
|
|
92
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
93
|
+
expect(err.code).toBe('AUTH');
|
|
94
|
+
expect(err.message).toContain('не поддерживает вход по логину/паролю');
|
|
95
|
+
});
|
|
96
|
+
it('404 + deps.defaultIssuer/defaultClientId → fallback на дефолты', async () => {
|
|
97
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonResponse({ error: 'not_found' }, 404)));
|
|
98
|
+
const conn = new RemoteConnection({ defaultIssuer: ISSUER, defaultClientId: CLIENT_ID });
|
|
99
|
+
const meta = await conn.discoverOidc(BACKEND);
|
|
100
|
+
expect(meta).toEqual({ issuer: ISSUER, clientId: CLIENT_ID });
|
|
101
|
+
});
|
|
102
|
+
it('404 без fallback → RemoteError(AUTH)', async () => {
|
|
103
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonResponse({ error: 'not_found' }, 404)));
|
|
104
|
+
const conn = new RemoteConnection({});
|
|
105
|
+
const err = await conn.discoverOidc(BACKEND).catch((e) => e);
|
|
106
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
107
|
+
expect(err.code).toBe('AUTH');
|
|
108
|
+
});
|
|
109
|
+
it('сеть недоступна + fallback есть → возвращает дефолты', async () => {
|
|
110
|
+
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new TypeError('Failed to fetch')));
|
|
111
|
+
const conn = new RemoteConnection({ defaultIssuer: ISSUER, defaultClientId: CLIENT_ID });
|
|
112
|
+
const meta = await conn.discoverOidc(BACKEND);
|
|
113
|
+
expect(meta).toEqual({ issuer: ISSUER, clientId: CLIENT_ID });
|
|
114
|
+
});
|
|
115
|
+
it('сеть недоступна без fallback → RemoteError(OFFLINE)', async () => {
|
|
116
|
+
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new TypeError('Failed to fetch')));
|
|
117
|
+
const conn = new RemoteConnection({});
|
|
118
|
+
const err = await conn.discoverOidc(BACKEND).catch((e) => e);
|
|
119
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
120
|
+
expect(err.code).toBe('OFFLINE');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe('RemoteConnection.connectByPassword', () => {
|
|
124
|
+
let dir;
|
|
125
|
+
beforeEach(async () => {
|
|
126
|
+
dir = await mkdtemp(join(tmpdir(), 'synth-conn-'));
|
|
127
|
+
});
|
|
128
|
+
afterEach(async () => {
|
|
129
|
+
await rm(dir, { recursive: true, force: true });
|
|
130
|
+
});
|
|
131
|
+
function credsPath() {
|
|
132
|
+
return join(dir, 'credentials.json');
|
|
133
|
+
}
|
|
134
|
+
it('успех: connected, user из /auth/status, client не null, backendUrl без завершающего /', async () => {
|
|
135
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock());
|
|
136
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
137
|
+
const user = await conn.connectByPassword('https://backend.test/', 'lucky', 'secret');
|
|
138
|
+
expect(user).toEqual(SERVER_USER);
|
|
139
|
+
expect(conn.connected).toBe(true);
|
|
140
|
+
expect(conn.backendUrl).toBe(BACKEND);
|
|
141
|
+
expect(conn.client).not.toBeNull();
|
|
142
|
+
expect(conn.user?.username).toBe('lucky');
|
|
143
|
+
expect(conn.issuer).toBe(ISSUER);
|
|
144
|
+
expect(conn.getToken).not.toBeNull();
|
|
145
|
+
expect(await conn.getToken?.()).toBe('at-ropc');
|
|
146
|
+
const saved = await loadCredentials(BACKEND, credsPath());
|
|
147
|
+
expect(saved?.accessToken).toBe('at-ropc');
|
|
148
|
+
expect(saved?.user?.username).toBe('lucky');
|
|
149
|
+
});
|
|
150
|
+
it('неверный пароль → RemoteError(AUTH), connected:false, состояние не фиксируется', async () => {
|
|
151
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock({
|
|
152
|
+
tokenStatus: 401,
|
|
153
|
+
tokenBody: { error: 'invalid_grant', error_description: 'Invalid user credentials' },
|
|
154
|
+
}));
|
|
155
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
156
|
+
const err = await conn.connectByPassword(BACKEND, 'lucky', 'wrong').catch((e) => e);
|
|
157
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
158
|
+
expect(err.code).toBe('AUTH');
|
|
159
|
+
expect(err.message).toContain('Неверный логин или пароль');
|
|
160
|
+
expect(conn.connected).toBe(false);
|
|
161
|
+
expect(conn.user).toBeNull();
|
|
162
|
+
expect(conn.backendUrl).toBeNull();
|
|
163
|
+
expect(conn.client).toBeNull();
|
|
164
|
+
// credentials не сохраняются при ошибке
|
|
165
|
+
expect(await loadCredentials(BACKEND, credsPath())).toBeNull();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe('RemoteConnection.connectWithApiKey', () => {
|
|
169
|
+
let dir;
|
|
170
|
+
beforeEach(async () => {
|
|
171
|
+
dir = await mkdtemp(join(tmpdir(), 'synth-conn-apikey-'));
|
|
172
|
+
});
|
|
173
|
+
afterEach(async () => {
|
|
174
|
+
await rm(dir, { recursive: true, force: true });
|
|
175
|
+
});
|
|
176
|
+
it('успех: connected, user из /auth/status, issuer null (без дискавери)', async () => {
|
|
177
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock());
|
|
178
|
+
const conn = new RemoteConnection({ credentialsPath: join(dir, 'credentials.json') });
|
|
179
|
+
const user = await conn.connectWithApiKey('https://backend.test/', 'api-key-1');
|
|
180
|
+
expect(user).toEqual(SERVER_USER);
|
|
181
|
+
expect(conn.connected).toBe(true);
|
|
182
|
+
expect(conn.backendUrl).toBe(BACKEND);
|
|
183
|
+
expect(conn.client).not.toBeNull();
|
|
184
|
+
expect(conn.user?.username).toBe('lucky');
|
|
185
|
+
expect(conn.issuer).toBeNull();
|
|
186
|
+
expect(await conn.getToken?.()).toBe('api-key-1');
|
|
187
|
+
// api_key-сессия ничего не пишет в credentials (это не OAuth-токен)
|
|
188
|
+
expect(await loadCredentials(BACKEND, join(dir, 'credentials.json'))).toBeNull();
|
|
189
|
+
});
|
|
190
|
+
it('пустой ключ → RemoteError(AUTH)', async () => {
|
|
191
|
+
const conn = new RemoteConnection({});
|
|
192
|
+
const err = await conn.connectWithApiKey(BACKEND, '').catch((e) => e);
|
|
193
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
194
|
+
expect(err.code).toBe('AUTH');
|
|
195
|
+
expect(conn.connected).toBe(false);
|
|
196
|
+
});
|
|
197
|
+
it('backend не отдаёт профиль (/auth/status без user) → RemoteError(AUTH), состояние не фиксируется', async () => {
|
|
198
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonResponse({ authenticated: true, oidc_enabled: true, user: null })));
|
|
199
|
+
const conn = new RemoteConnection({});
|
|
200
|
+
const err = await conn.connectWithApiKey(BACKEND, 'api-key-1').catch((e) => e);
|
|
201
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
202
|
+
expect(err.code).toBe('AUTH');
|
|
203
|
+
expect(conn.connected).toBe(false);
|
|
204
|
+
expect(conn.backendUrl).toBeNull();
|
|
205
|
+
});
|
|
206
|
+
it('backend недоступен (сеть) → RemoteError(AUTH), состояние не фиксируется', async () => {
|
|
207
|
+
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new TypeError('Failed to fetch')));
|
|
208
|
+
const conn = new RemoteConnection({});
|
|
209
|
+
const err = await conn.connectWithApiKey(BACKEND, 'api-key-1').catch((e) => e);
|
|
210
|
+
expect(err).toBeInstanceOf(RemoteError);
|
|
211
|
+
expect(conn.connected).toBe(false);
|
|
212
|
+
expect(conn.client).toBeNull();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('RemoteConnection.connectFromSaved', () => {
|
|
216
|
+
let dir;
|
|
217
|
+
beforeEach(async () => {
|
|
218
|
+
dir = await mkdtemp(join(tmpdir(), 'synth-conn-saved-'));
|
|
219
|
+
});
|
|
220
|
+
afterEach(async () => {
|
|
221
|
+
await rm(dir, { recursive: true, force: true });
|
|
222
|
+
});
|
|
223
|
+
function credsPath() {
|
|
224
|
+
return join(dir, 'credentials.json');
|
|
225
|
+
}
|
|
226
|
+
function validCreds(overrides = {}) {
|
|
227
|
+
return {
|
|
228
|
+
backendUrl: BACKEND,
|
|
229
|
+
accessToken: 'at-valid',
|
|
230
|
+
refreshToken: 'rt-1',
|
|
231
|
+
expiresAt: new Date(Date.now() + 3_600_000).toISOString(),
|
|
232
|
+
user: { id: 'u-saved', username: 'admin', roles: ['ADMIN'] },
|
|
233
|
+
...overrides,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
it('без credentials → null, connected:false, fetch не вызывался (нет device flow)', async () => {
|
|
237
|
+
const fetchMock = vi.fn();
|
|
238
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
239
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
240
|
+
const user = await conn.connectFromSaved(BACKEND);
|
|
241
|
+
expect(user).toBeNull();
|
|
242
|
+
expect(conn.connected).toBe(false);
|
|
243
|
+
expect(conn.user).toBeNull();
|
|
244
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
245
|
+
});
|
|
246
|
+
it('валидный accessToken в credentials → connected, user обновлён с /auth/status', async () => {
|
|
247
|
+
await saveCredentials(validCreds(), credsPath());
|
|
248
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock());
|
|
249
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
250
|
+
const user = await conn.connectFromSaved(BACKEND);
|
|
251
|
+
expect(user?.username).toBe('lucky');
|
|
252
|
+
expect(conn.connected).toBe(true);
|
|
253
|
+
expect(conn.backendUrl).toBe(BACKEND);
|
|
254
|
+
expect(conn.client).not.toBeNull();
|
|
255
|
+
expect(conn.issuer).toBe(ISSUER);
|
|
256
|
+
// токен не обновлялся — в файле остался исходный
|
|
257
|
+
const saved = await loadCredentials(BACKEND, credsPath());
|
|
258
|
+
expect(saved?.accessToken).toBe('at-valid');
|
|
259
|
+
});
|
|
260
|
+
it('протухший accessToken + refreshToken → дискавери + refresh, connected, credentials обновлены', async () => {
|
|
261
|
+
await saveCredentials(validCreds({
|
|
262
|
+
accessToken: 'at-old',
|
|
263
|
+
refreshToken: 'rt-old',
|
|
264
|
+
expiresAt: '2020-01-01T00:00:00.000Z',
|
|
265
|
+
user: { id: 'u-saved', username: 'admin', roles: ['ADMIN'] },
|
|
266
|
+
}), credsPath());
|
|
267
|
+
vi.stubGlobal('fetch', refreshFlowFetchMock());
|
|
268
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
269
|
+
const user = await conn.connectFromSaved(BACKEND);
|
|
270
|
+
expect(user?.username).toBe('lucky');
|
|
271
|
+
expect(conn.connected).toBe(true);
|
|
272
|
+
expect(conn.issuer).toBe(ISSUER);
|
|
273
|
+
const saved = await loadCredentials(BACKEND, credsPath());
|
|
274
|
+
expect(saved?.accessToken).toBe('at-refreshed');
|
|
275
|
+
expect(saved?.refreshToken).toBe('rt-refreshed');
|
|
276
|
+
});
|
|
277
|
+
it('backendUrl не передан → берёт сохранённые credentials из файла', async () => {
|
|
278
|
+
await saveCredentials(validCreds(), credsPath());
|
|
279
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock());
|
|
280
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
281
|
+
const user = await conn.connectFromSaved();
|
|
282
|
+
expect(user?.username).toBe('lucky');
|
|
283
|
+
expect(conn.connected).toBe(true);
|
|
284
|
+
expect(conn.backendUrl).toBe(BACKEND);
|
|
285
|
+
});
|
|
286
|
+
it('протух без refreshToken → null, connected:false', async () => {
|
|
287
|
+
await saveCredentials(validCreds({
|
|
288
|
+
accessToken: 'at-old',
|
|
289
|
+
expiresAt: '2020-01-01T00:00:00.000Z',
|
|
290
|
+
refreshToken: undefined,
|
|
291
|
+
}), credsPath());
|
|
292
|
+
const fetchMock = vi.fn();
|
|
293
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
294
|
+
const conn = new RemoteConnection({ credentialsPath: credsPath() });
|
|
295
|
+
const user = await conn.connectFromSaved(BACKEND);
|
|
296
|
+
expect(user).toBeNull();
|
|
297
|
+
expect(conn.connected).toBe(false);
|
|
298
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
describe('RemoteConnection.disconnect', () => {
|
|
302
|
+
let dir;
|
|
303
|
+
beforeEach(async () => {
|
|
304
|
+
dir = await mkdtemp(join(tmpdir(), 'synth-conn-disc-'));
|
|
305
|
+
});
|
|
306
|
+
afterEach(async () => {
|
|
307
|
+
await rm(dir, { recursive: true, force: true });
|
|
308
|
+
});
|
|
309
|
+
it('сбрасывает состояние: connected:false, client null, user null, backendUrl null', async () => {
|
|
310
|
+
vi.stubGlobal('fetch', passwordFlowFetchMock());
|
|
311
|
+
const conn = new RemoteConnection({ credentialsPath: join(dir, 'credentials.json') });
|
|
312
|
+
await conn.connectByPassword(BACKEND, 'lucky', 'secret');
|
|
313
|
+
expect(conn.connected).toBe(true);
|
|
314
|
+
conn.disconnect();
|
|
315
|
+
expect(conn.connected).toBe(false);
|
|
316
|
+
expect(conn.client).toBeNull();
|
|
317
|
+
expect(conn.getToken).toBeNull();
|
|
318
|
+
expect(conn.user).toBeNull();
|
|
319
|
+
expect(conn.backendUrl).toBeNull();
|
|
320
|
+
expect(conn.issuer).toBeNull();
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
//# sourceMappingURL=connection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.test.js","sourceRoot":"","sources":["../../src/remote/connection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RemoteCredentials } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Загрузить credentials для backendUrl.
|
|
4
|
+
* Возвращает null, если файл отсутствует/повреждён или сохранённый backendUrl не совпадает.
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadCredentials(backendUrl: string, path?: string): Promise<RemoteCredentials | null>;
|
|
7
|
+
/** Сохранить credentials (дозапись в общий файл, атомарно, права 0600). */
|
|
8
|
+
export declare function saveCredentials(creds: RemoteCredentials, path?: string): Promise<void>;
|
|
9
|
+
/** Список backendUrl, для которых сохранены credentials (порядок файла). */
|
|
10
|
+
export declare function listCredentials(path?: string): Promise<string[]>;
|
|
11
|
+
/** Удалить credentials для backendUrl. Если записей не осталось — удалить файл. */
|
|
12
|
+
export declare function clearCredentials(backendUrl: string, path?: string): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/remote/credentials.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAmCpD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAM1G;AAED,2EAA2E;AAC3E,wBAAsB,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5F;AAED,4EAA4E;AAC5E,wBAAsB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGtE;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Хранилище credentials для гибридного режима (AD-005: атомарная запись tmp + rename).
|
|
2
|
+
//
|
|
3
|
+
// Файл credentials — JSON-объект Record<backendUrl, RemoteCredentials>:
|
|
4
|
+
// {
|
|
5
|
+
// "https://synth.k3s.itphx.loc": {
|
|
6
|
+
// "backendUrl": "https://synth.k3s.itphx.loc",
|
|
7
|
+
// "accessToken": "...",
|
|
8
|
+
// "refreshToken": "...",
|
|
9
|
+
// "expiresAt": "2026-09-01T00:00:00.000Z",
|
|
10
|
+
// "user": { "id": "...", "username": "admin", "roles": ["ADMIN"] }
|
|
11
|
+
// }
|
|
12
|
+
// }
|
|
13
|
+
// Один файл может хранить credentials для нескольких backend-серверов.
|
|
14
|
+
// По умолчанию путь — ~/.config/synth/credentials.json.
|
|
15
|
+
import { readFile, writeFile, rename, mkdir, unlink } from 'node:fs/promises';
|
|
16
|
+
import { join, dirname } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
import { atomicWrite } from '@itphx/synth-shared';
|
|
19
|
+
/** Права файла credentials: только владелец (0600). */
|
|
20
|
+
const CREDENTIALS_FILE_MODE = 0o600;
|
|
21
|
+
function defaultCredentialsPath() {
|
|
22
|
+
return join(homedir(), '.config', 'synth', 'credentials.json');
|
|
23
|
+
}
|
|
24
|
+
async function readCredentialsFile(path) {
|
|
25
|
+
try {
|
|
26
|
+
const data = await readFile(path, 'utf-8');
|
|
27
|
+
const parsed = JSON.parse(data);
|
|
28
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function writeCredentialsFile(path, file) {
|
|
38
|
+
await mkdir(dirname(path), { recursive: true });
|
|
39
|
+
const data = JSON.stringify(file, null, 2);
|
|
40
|
+
await atomicWrite((p, d) => writeFile(p, d, { encoding: 'utf-8', mode: CREDENTIALS_FILE_MODE }), (o, n) => rename(o, n), path, data);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Загрузить credentials для backendUrl.
|
|
44
|
+
* Возвращает null, если файл отсутствует/повреждён или сохранённый backendUrl не совпадает.
|
|
45
|
+
*/
|
|
46
|
+
export async function loadCredentials(backendUrl, path) {
|
|
47
|
+
const file = await readCredentialsFile(path ?? defaultCredentialsPath());
|
|
48
|
+
const entry = file[backendUrl];
|
|
49
|
+
if (!entry)
|
|
50
|
+
return null;
|
|
51
|
+
if (entry.backendUrl !== backendUrl)
|
|
52
|
+
return null;
|
|
53
|
+
return entry;
|
|
54
|
+
}
|
|
55
|
+
/** Сохранить credentials (дозапись в общий файл, атомарно, права 0600). */
|
|
56
|
+
export async function saveCredentials(creds, path) {
|
|
57
|
+
const filePath = path ?? defaultCredentialsPath();
|
|
58
|
+
const file = await readCredentialsFile(filePath);
|
|
59
|
+
file[creds.backendUrl] = creds;
|
|
60
|
+
await writeCredentialsFile(filePath, file);
|
|
61
|
+
}
|
|
62
|
+
/** Список backendUrl, для которых сохранены credentials (порядок файла). */
|
|
63
|
+
export async function listCredentials(path) {
|
|
64
|
+
const file = await readCredentialsFile(path ?? defaultCredentialsPath());
|
|
65
|
+
return Object.keys(file);
|
|
66
|
+
}
|
|
67
|
+
/** Удалить credentials для backendUrl. Если записей не осталось — удалить файл. */
|
|
68
|
+
export async function clearCredentials(backendUrl, path) {
|
|
69
|
+
const filePath = path ?? defaultCredentialsPath();
|
|
70
|
+
const file = await readCredentialsFile(filePath);
|
|
71
|
+
if (!file[backendUrl])
|
|
72
|
+
return;
|
|
73
|
+
delete file[backendUrl];
|
|
74
|
+
const remaining = Object.keys(file).length;
|
|
75
|
+
if (remaining === 0) {
|
|
76
|
+
await unlink(filePath).catch(() => { });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
await writeCredentialsFile(filePath, file);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/remote/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.test.d.ts","sourceRoot":"","sources":["../../src/remote/credentials.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtemp, rm, stat, access } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { loadCredentials, saveCredentials, clearCredentials } from './credentials.js';
|
|
6
|
+
describe('credentials', () => {
|
|
7
|
+
let dir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
dir = await mkdtemp(join(tmpdir(), 'synth-cred-'));
|
|
10
|
+
});
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await rm(dir, { recursive: true, force: true });
|
|
13
|
+
});
|
|
14
|
+
function filePath(name = 'credentials.json') {
|
|
15
|
+
return join(dir, name);
|
|
16
|
+
}
|
|
17
|
+
function makeCreds(overrides = {}) {
|
|
18
|
+
return {
|
|
19
|
+
backendUrl: 'https://synth.example.loc',
|
|
20
|
+
accessToken: 'token-1',
|
|
21
|
+
refreshToken: 'refresh-1',
|
|
22
|
+
expiresAt: '2026-09-01T00:00:00.000Z',
|
|
23
|
+
user: { id: 'u1', username: 'admin', roles: ['ADMIN'] },
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
it('round-trip: save → load возвращает те же credentials', async () => {
|
|
28
|
+
const creds = makeCreds();
|
|
29
|
+
await saveCredentials(creds, filePath());
|
|
30
|
+
const loaded = await loadCredentials(creds.backendUrl, filePath());
|
|
31
|
+
expect(loaded).toEqual(creds);
|
|
32
|
+
});
|
|
33
|
+
it('файл credentials имеет права 0600', async () => {
|
|
34
|
+
await saveCredentials(makeCreds(), filePath());
|
|
35
|
+
const st = await stat(filePath());
|
|
36
|
+
expect(st.mode & 0o777).toBe(0o600);
|
|
37
|
+
});
|
|
38
|
+
it('хранит несколько backendUrl в одном файле', async () => {
|
|
39
|
+
const a = makeCreds({ backendUrl: 'https://a.example.loc', accessToken: 'a' });
|
|
40
|
+
const b = makeCreds({ backendUrl: 'https://b.example.loc', accessToken: 'b' });
|
|
41
|
+
await saveCredentials(a, filePath());
|
|
42
|
+
await saveCredentials(b, filePath());
|
|
43
|
+
expect(await loadCredentials(a.backendUrl, filePath())).toEqual(a);
|
|
44
|
+
expect(await loadCredentials(b.backendUrl, filePath())).toEqual(b);
|
|
45
|
+
});
|
|
46
|
+
it('clear удаляет запись; при пустом файле файл удаляется', async () => {
|
|
47
|
+
await saveCredentials(makeCreds(), filePath());
|
|
48
|
+
await clearCredentials('https://synth.example.loc', filePath());
|
|
49
|
+
expect(await loadCredentials('https://synth.example.loc', filePath())).toBeNull();
|
|
50
|
+
await expect(access(filePath())).rejects.toThrow();
|
|
51
|
+
});
|
|
52
|
+
it('clear не трогает записи других backendUrl', async () => {
|
|
53
|
+
const a = makeCreds({ backendUrl: 'https://a.example.loc', accessToken: 'a' });
|
|
54
|
+
const b = makeCreds({ backendUrl: 'https://b.example.loc', accessToken: 'b' });
|
|
55
|
+
await saveCredentials(a, filePath());
|
|
56
|
+
await saveCredentials(b, filePath());
|
|
57
|
+
await clearCredentials(a.backendUrl, filePath());
|
|
58
|
+
expect(await loadCredentials(a.backendUrl, filePath())).toBeNull();
|
|
59
|
+
expect(await loadCredentials(b.backendUrl, filePath())).toEqual(b);
|
|
60
|
+
});
|
|
61
|
+
it('несовпадение backendUrl → null', async () => {
|
|
62
|
+
await saveCredentials(makeCreds({ backendUrl: 'https://a.example.loc' }), filePath());
|
|
63
|
+
expect(await loadCredentials('https://b.example.loc', filePath())).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
it('отсутствующий файл → null', async () => {
|
|
66
|
+
expect(await loadCredentials('https://a.example.loc', filePath('missing.json'))).toBeNull();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=credentials.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.test.js","sourceRoot":"","sources":["../../src/remote/credentials.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { RemoteErrorCode } from './types.js';
|
|
2
|
+
export interface DeviceFlowDiscovery {
|
|
3
|
+
token_endpoint: string;
|
|
4
|
+
device_authorization_endpoint: string;
|
|
5
|
+
issuer: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DeviceFlowSession {
|
|
8
|
+
deviceCode: string;
|
|
9
|
+
userCode: string;
|
|
10
|
+
verificationUri: string;
|
|
11
|
+
verificationUriComplete?: string;
|
|
12
|
+
expiresIn: number;
|
|
13
|
+
interval: number;
|
|
14
|
+
tokenEndpoint: string;
|
|
15
|
+
/** client_id из startDeviceFlow — обязателен в token-запросе (RFC 8628 §3.4). */
|
|
16
|
+
clientId: string;
|
|
17
|
+
}
|
|
18
|
+
export interface DeviceTokenResult {
|
|
19
|
+
accessToken: string;
|
|
20
|
+
refreshToken?: string;
|
|
21
|
+
expiresIn?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface RefreshTokenResult {
|
|
24
|
+
accessToken: string;
|
|
25
|
+
refreshToken?: string;
|
|
26
|
+
expiresIn?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Результат входа по логину/паролю (ROPC, grant_type=password). */
|
|
29
|
+
export interface PasswordGrantResult {
|
|
30
|
+
accessToken: string;
|
|
31
|
+
refreshToken?: string;
|
|
32
|
+
expiresIn?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Параметры postForm: код ошибки при недоступности сервера авторизации. */
|
|
35
|
+
export interface PostFormOptions {
|
|
36
|
+
networkErrorCode?: RemoteErrorCode;
|
|
37
|
+
}
|
|
38
|
+
export declare function postForm(url: string, params: URLSearchParams, opts?: PostFormOptions): Promise<Record<string, unknown>>;
|
|
39
|
+
/**
|
|
40
|
+
* Получить конфигурацию OIDC-провайдера: GET {issuer}/.well-known/openid-configuration.
|
|
41
|
+
* Возвращает только endpoint-ы, нужные для device flow.
|
|
42
|
+
*/
|
|
43
|
+
export declare function discover(issuer: string): Promise<DeviceFlowDiscovery>;
|
|
44
|
+
/**
|
|
45
|
+
* Начать device flow: запросить device_code/user_code у сервера авторизации.
|
|
46
|
+
* Возвращает сессию, по которой нужно показать пользователю user_code и verification_uri.
|
|
47
|
+
*/
|
|
48
|
+
export declare function startDeviceFlow(issuer: string, clientId: string): Promise<DeviceFlowSession>;
|
|
49
|
+
/**
|
|
50
|
+
* Опрашивать token_endpoint, пока пользователь не подтвердит авторизацию.
|
|
51
|
+
* - authorization_pending → ждём interval и продолжаем;
|
|
52
|
+
* - slow_down → добавляем 5 секунд к ожиданию;
|
|
53
|
+
* - expired_token / access_denied → RemoteError('AUTH') с понятным сообщением.
|
|
54
|
+
* onPoll вызывается перед каждой попыткой (начиная с 1).
|
|
55
|
+
*/
|
|
56
|
+
export declare function pollDeviceToken(session: DeviceFlowSession, onPoll?: (attempt: number) => void, timeoutMs?: number): Promise<DeviceTokenResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Обновить access token по refresh token (grant_type=refresh_token, RFC 6749 §6).
|
|
59
|
+
* Ошибки (в т.ч. invalid_grant) → RemoteError('AUTH') с понятным сообщением.
|
|
60
|
+
*/
|
|
61
|
+
export declare function refreshAccessToken(issuer: string, clientId: string, refreshToken: string): Promise<RefreshTokenResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Вход по логину/паролю (ROPC, grant_type=password, RFC 6749 §4.3).
|
|
64
|
+
* Используется в гибридном режиме для «единой личности»: локальный core
|
|
65
|
+
* логинится как серверный пользователь Keycloak (public-клиент с
|
|
66
|
+
* directAccessGrantsEnabled). Токен-эндпоинт — стандартный путь Keycloak
|
|
67
|
+
* {issuer}/protocol/openid-connect/token.
|
|
68
|
+
* Ошибки аутентификации (invalid_grant/invalid_client) → RemoteError('AUTH')
|
|
69
|
+
* с понятным русским сообщением; сеть недоступна → RemoteError('OFFLINE').
|
|
70
|
+
*/
|
|
71
|
+
export declare function passwordGrant(issuer: string, clientId: string, username: string, password: string): Promise<PasswordGrantResult>;
|
|
72
|
+
//# sourceMappingURL=device-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/remote/device-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,6BAA6B,EAAE,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC;AA0BD,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAuBlC;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAa3E;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiClG;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAClC,SAAS,GAAE,MAAgC,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CA6C5B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAsB7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CA4B9B"}
|