hazo_auth 9.1.1 → 10.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.
- package/README.md +124 -6
- package/SETUP_CHECKLIST.md +24 -16
- package/cli-src/cli/init_users.ts +40 -48
- package/cli-src/lib/auth/auth_types.ts +0 -2
- package/cli-src/lib/auth/hazo_get_auth.server.ts +31 -25
- package/cli-src/lib/auth/hazo_get_tenant_auth.server.ts +9 -13
- package/cli-src/lib/auth/nextauth_config.ts +41 -0
- package/cli-src/lib/auth/request_google_scopes.ts +23 -0
- package/cli-src/lib/constants.ts +2 -0
- package/cli-src/lib/profile_pic_menu_config.server.ts +4 -3
- package/cli-src/lib/schema/sqlite_schema.ts +16 -4
- package/cli-src/lib/scope_hierarchy_config.server.ts +1 -9
- package/cli-src/lib/services/google_token_service.ts +408 -0
- package/cli-src/lib/services/index.ts +1 -1
- package/cli-src/lib/services/invitation_service.ts +1 -1
- package/cli-src/lib/services/scope_service.ts +2 -76
- package/cli-src/lib/services/user_scope_service.ts +7 -61
- package/dist/cli/init_users.d.ts.map +1 -1
- package/dist/cli/init_users.js +42 -42
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/components/layouts/google_token_test/index.d.ts +6 -0
- package/dist/components/layouts/google_token_test/index.d.ts.map +1 -0
- package/dist/components/layouts/google_token_test/index.js +74 -0
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +7 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/lib/auth/auth_types.d.ts +0 -2
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +27 -19
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_tenant_auth.server.js +10 -10
- package/dist/lib/auth/nextauth_config.d.ts +2 -0
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.js +39 -1
- package/dist/lib/auth/request_google_scopes.d.ts +10 -0
- package/dist/lib/auth/request_google_scopes.d.ts.map +1 -0
- package/dist/lib/auth/request_google_scopes.js +13 -0
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -0
- package/dist/lib/profile_pic_menu_config.server.d.ts +2 -1
- package/dist/lib/profile_pic_menu_config.server.d.ts.map +1 -1
- package/dist/lib/profile_pic_menu_config.server.js +1 -1
- package/dist/lib/schema/sqlite_schema.d.ts +1 -1
- package/dist/lib/schema/sqlite_schema.d.ts.map +1 -1
- package/dist/lib/schema/sqlite_schema.js +16 -4
- package/dist/lib/scope_hierarchy_config.server.d.ts +0 -2
- package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -1
- package/dist/lib/scope_hierarchy_config.server.js +1 -3
- package/dist/lib/services/google_token_service.d.ts +48 -0
- package/dist/lib/services/google_token_service.d.ts.map +1 -0
- package/dist/lib/services/google_token_service.js +319 -0
- package/dist/lib/services/index.d.ts +1 -0
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/services/invitation_service.d.ts +1 -1
- package/dist/lib/services/invitation_service.js +1 -1
- package/dist/lib/services/scope_service.d.ts +1 -14
- package/dist/lib/services/scope_service.d.ts.map +1 -1
- package/dist/lib/services/scope_service.js +2 -67
- package/dist/lib/services/user_scope_service.d.ts +5 -12
- package/dist/lib/services/user_scope_service.d.ts.map +1 -1
- package/dist/lib/services/user_scope_service.js +8 -45
- package/dist/server/routes/google_token.d.ts +13 -0
- package/dist/server/routes/google_token.d.ts.map +1 -0
- package/dist/server/routes/google_token.js +66 -0
- package/dist/server/routes/index.d.ts +1 -0
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +2 -0
- package/dist/server/routes/invitations.d.ts +1 -1
- package/dist/server/routes/invitations.d.ts.map +1 -1
- package/dist/server/routes/invitations.js +12 -11
- package/dist/server/routes/user_management_users.d.ts +1 -1
- package/package.json +17 -13
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// file_description: stores, retrieves, refreshes, and revokes Google OAuth tokens with encrypted persistence
|
|
2
|
+
// section: imports
|
|
3
|
+
import { createCrudService } from "hazo_connect/server";
|
|
4
|
+
import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
|
|
5
|
+
import { create_app_logger } from "../app_logger.js";
|
|
6
|
+
import { optional_import } from "hazo_core";
|
|
7
|
+
import { randomUUID } from "crypto";
|
|
8
|
+
// section: errors
|
|
9
|
+
export class GoogleTokenStorageUnconfigured extends Error {
|
|
10
|
+
constructor() {
|
|
11
|
+
super("Google token storage is not configured. Set HAZO_AUTH_OAUTH_KEY_CURRENT and HAZO_AUTH_OAUTH_KEY_<ID> env vars.");
|
|
12
|
+
this.name = "GoogleTokenStorageUnconfigured";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// section: cache
|
|
16
|
+
const access_token_cache = new Map();
|
|
17
|
+
// section: helpers
|
|
18
|
+
function makeKeyProvider(LookupKeyProvider) {
|
|
19
|
+
return new LookupKeyProvider((name) => {
|
|
20
|
+
if (name === "current")
|
|
21
|
+
return process.env.HAZO_AUTH_OAUTH_KEY_CURRENT;
|
|
22
|
+
if (name.startsWith("key_")) {
|
|
23
|
+
const keyId = name.slice(4).toUpperCase();
|
|
24
|
+
return process.env[`HAZO_AUTH_OAUTH_KEY_${keyId}`];
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function load_crypto_module() {
|
|
30
|
+
const cryptoModule = await optional_import("hazo_secure/crypto");
|
|
31
|
+
if (!cryptoModule)
|
|
32
|
+
throw new GoogleTokenStorageUnconfigured();
|
|
33
|
+
return cryptoModule;
|
|
34
|
+
}
|
|
35
|
+
// section: store
|
|
36
|
+
/**
|
|
37
|
+
* Stores (inserts or updates) Google OAuth tokens for a user, encrypting sensitive fields.
|
|
38
|
+
* Throws GoogleTokenStorageUnconfigured if hazo_secure/crypto is unavailable or keys are missing.
|
|
39
|
+
*/
|
|
40
|
+
export async function store_google_oauth_token(params) {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
const logger = create_app_logger();
|
|
43
|
+
const { encryptField, decryptField: _decryptField, aadFor, LookupKeyProvider } = await load_crypto_module();
|
|
44
|
+
const keys = makeKeyProvider(LookupKeyProvider);
|
|
45
|
+
// Force-fail early if no key is configured
|
|
46
|
+
try {
|
|
47
|
+
await keys.current();
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
+
logger.error("google_token_service_key_provider_failed", {
|
|
52
|
+
filename: "google_token_service.ts",
|
|
53
|
+
error: msg,
|
|
54
|
+
});
|
|
55
|
+
throw new GoogleTokenStorageUnconfigured();
|
|
56
|
+
}
|
|
57
|
+
const refresh_enc = await encryptField(params.refresh_token, {
|
|
58
|
+
keys,
|
|
59
|
+
aad: aadFor("hazo_google_oauth_tokens", params.user_id, "refresh_token"),
|
|
60
|
+
});
|
|
61
|
+
const refresh_token_enc = JSON.stringify(refresh_enc);
|
|
62
|
+
let access_token_enc = null;
|
|
63
|
+
if (params.access_token) {
|
|
64
|
+
const access_enc = await encryptField(params.access_token, {
|
|
65
|
+
keys,
|
|
66
|
+
aad: aadFor("hazo_google_oauth_tokens", params.user_id, "access_token"),
|
|
67
|
+
});
|
|
68
|
+
access_token_enc = JSON.stringify(access_enc);
|
|
69
|
+
}
|
|
70
|
+
const adapter = get_hazo_connect_instance();
|
|
71
|
+
const service = createCrudService(adapter, "hazo_google_oauth_tokens");
|
|
72
|
+
const existing_rows = (await service.findBy({
|
|
73
|
+
user_id: params.user_id,
|
|
74
|
+
provider: "google",
|
|
75
|
+
}));
|
|
76
|
+
const now = new Date().toISOString();
|
|
77
|
+
if (existing_rows.length > 0) {
|
|
78
|
+
const existing = existing_rows[0];
|
|
79
|
+
await service.updateById(existing.id, {
|
|
80
|
+
refresh_token_enc,
|
|
81
|
+
access_token_enc,
|
|
82
|
+
scopes: params.scopes,
|
|
83
|
+
expires_at: (_a = params.expires_at) !== null && _a !== void 0 ? _a : null,
|
|
84
|
+
changed_at: now,
|
|
85
|
+
});
|
|
86
|
+
logger.info("google_token_service_token_updated", {
|
|
87
|
+
filename: "google_token_service.ts",
|
|
88
|
+
user_id: params.user_id,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await service.insert({
|
|
93
|
+
id: randomUUID(),
|
|
94
|
+
user_id: params.user_id,
|
|
95
|
+
provider: "google",
|
|
96
|
+
refresh_token_enc,
|
|
97
|
+
access_token_enc,
|
|
98
|
+
scopes: params.scopes,
|
|
99
|
+
expires_at: (_b = params.expires_at) !== null && _b !== void 0 ? _b : null,
|
|
100
|
+
created_at: now,
|
|
101
|
+
changed_at: now,
|
|
102
|
+
});
|
|
103
|
+
logger.info("google_token_service_token_stored", {
|
|
104
|
+
filename: "google_token_service.ts",
|
|
105
|
+
user_id: params.user_id,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// section: get
|
|
110
|
+
/**
|
|
111
|
+
* Returns a valid access token for the user, refreshing via Google if needed.
|
|
112
|
+
* Returns a typed error result instead of throwing for expected failure modes.
|
|
113
|
+
*/
|
|
114
|
+
export async function getGoogleToken(userId, opts) {
|
|
115
|
+
var _a, _b;
|
|
116
|
+
const logger = create_app_logger();
|
|
117
|
+
// Check in-memory cache first
|
|
118
|
+
const cached = access_token_cache.get(userId);
|
|
119
|
+
if (cached) {
|
|
120
|
+
const still_valid = new Date(cached.expires_at).getTime() - 60000 > Date.now();
|
|
121
|
+
if (still_valid) {
|
|
122
|
+
logger.info("google_token_service_cache_hit", {
|
|
123
|
+
filename: "google_token_service.ts",
|
|
124
|
+
user_id: userId,
|
|
125
|
+
});
|
|
126
|
+
// We need scopes from DB even on cache hit when scope check is requested
|
|
127
|
+
if (!((_a = opts === null || opts === void 0 ? void 0 : opts.scopes) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
128
|
+
// No scope check needed — return cached token (scopes unknown from cache alone)
|
|
129
|
+
// Fall through to DB to get scopes for the result shape
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const adapter = get_hazo_connect_instance();
|
|
134
|
+
const service = createCrudService(adapter, "hazo_google_oauth_tokens");
|
|
135
|
+
const rows = (await service.findBy({ user_id: userId, provider: "google" }));
|
|
136
|
+
if (rows.length === 0) {
|
|
137
|
+
return { ok: false, error: "not_connected" };
|
|
138
|
+
}
|
|
139
|
+
const row = rows[0];
|
|
140
|
+
// Scope check
|
|
141
|
+
if ((_b = opts === null || opts === void 0 ? void 0 : opts.scopes) === null || _b === void 0 ? void 0 : _b.length) {
|
|
142
|
+
const stored_scopes = row.scopes.split(" ").filter(Boolean);
|
|
143
|
+
const missing = opts.scopes.some((s) => !stored_scopes.includes(s));
|
|
144
|
+
if (missing) {
|
|
145
|
+
return { ok: false, error: "reconsent_required" };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Return cached token now that we have the row (scope check passed)
|
|
149
|
+
if (cached) {
|
|
150
|
+
const still_valid = new Date(cached.expires_at).getTime() - 60000 > Date.now();
|
|
151
|
+
if (still_valid) {
|
|
152
|
+
return { ok: true, access_token: cached.token, scopes: row.scopes };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Need to refresh — load crypto
|
|
156
|
+
let cryptoModule;
|
|
157
|
+
try {
|
|
158
|
+
cryptoModule = await load_crypto_module();
|
|
159
|
+
}
|
|
160
|
+
catch (_c) {
|
|
161
|
+
return { ok: false, error: "unconfigured" };
|
|
162
|
+
}
|
|
163
|
+
const { decryptField, aadFor, LookupKeyProvider } = cryptoModule;
|
|
164
|
+
const keys = makeKeyProvider(LookupKeyProvider);
|
|
165
|
+
let decrypted_refresh;
|
|
166
|
+
try {
|
|
167
|
+
decrypted_refresh = await decryptField(JSON.parse(row.refresh_token_enc), {
|
|
168
|
+
keys,
|
|
169
|
+
aad: aadFor("hazo_google_oauth_tokens", userId, "refresh_token"),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
174
|
+
logger.error("google_token_service_decrypt_failed", {
|
|
175
|
+
filename: "google_token_service.ts",
|
|
176
|
+
user_id: userId,
|
|
177
|
+
error: msg,
|
|
178
|
+
});
|
|
179
|
+
return { ok: false, error: "refresh_failed" };
|
|
180
|
+
}
|
|
181
|
+
// Call Google token refresh endpoint
|
|
182
|
+
let resp;
|
|
183
|
+
try {
|
|
184
|
+
resp = await fetch("https://oauth2.googleapis.com/token", {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
187
|
+
body: new URLSearchParams({
|
|
188
|
+
grant_type: "refresh_token",
|
|
189
|
+
refresh_token: decrypted_refresh,
|
|
190
|
+
client_id: process.env.HAZO_AUTH_GOOGLE_CLIENT_ID,
|
|
191
|
+
client_secret: process.env.HAZO_AUTH_GOOGLE_CLIENT_SECRET,
|
|
192
|
+
}),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
197
|
+
logger.error("google_token_service_refresh_fetch_failed", {
|
|
198
|
+
filename: "google_token_service.ts",
|
|
199
|
+
user_id: userId,
|
|
200
|
+
error: msg,
|
|
201
|
+
});
|
|
202
|
+
return { ok: false, error: "refresh_failed" };
|
|
203
|
+
}
|
|
204
|
+
if (!resp.ok) {
|
|
205
|
+
logger.warn("google_token_service_refresh_rejected", {
|
|
206
|
+
filename: "google_token_service.ts",
|
|
207
|
+
user_id: userId,
|
|
208
|
+
status: resp.status,
|
|
209
|
+
});
|
|
210
|
+
return { ok: false, error: "refresh_failed" };
|
|
211
|
+
}
|
|
212
|
+
const data = await resp.json();
|
|
213
|
+
// Persist new access token (encrypted)
|
|
214
|
+
const new_expires_at = new Date(Date.now() + data.expires_in * 1000).toISOString();
|
|
215
|
+
try {
|
|
216
|
+
const { encryptField } = cryptoModule;
|
|
217
|
+
const access_enc = await encryptField(data.access_token, {
|
|
218
|
+
keys,
|
|
219
|
+
aad: aadFor("hazo_google_oauth_tokens", userId, "access_token"),
|
|
220
|
+
});
|
|
221
|
+
const access_token_enc = JSON.stringify(access_enc);
|
|
222
|
+
await service.updateById(row.id, {
|
|
223
|
+
access_token_enc,
|
|
224
|
+
expires_at: new_expires_at,
|
|
225
|
+
changed_at: new Date().toISOString(),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
230
|
+
logger.warn("google_token_service_persist_access_token_failed", {
|
|
231
|
+
filename: "google_token_service.ts",
|
|
232
|
+
user_id: userId,
|
|
233
|
+
error: msg,
|
|
234
|
+
note: "Access token refreshed successfully but could not be persisted",
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// Update in-memory cache
|
|
238
|
+
access_token_cache.set(userId, { token: data.access_token, expires_at: new_expires_at });
|
|
239
|
+
logger.info("google_token_service_token_refreshed", {
|
|
240
|
+
filename: "google_token_service.ts",
|
|
241
|
+
user_id: userId,
|
|
242
|
+
});
|
|
243
|
+
return { ok: true, access_token: data.access_token, scopes: row.scopes };
|
|
244
|
+
}
|
|
245
|
+
// section: revoke
|
|
246
|
+
/**
|
|
247
|
+
* Revokes the user's Google OAuth tokens — best-effort remote revocation, then deletes DB row.
|
|
248
|
+
*/
|
|
249
|
+
export async function revoke_google_oauth_token(userId) {
|
|
250
|
+
const logger = create_app_logger();
|
|
251
|
+
const adapter = get_hazo_connect_instance();
|
|
252
|
+
const service = createCrudService(adapter, "hazo_google_oauth_tokens");
|
|
253
|
+
const rows = (await service.findBy({ user_id: userId, provider: "google" }));
|
|
254
|
+
if (rows.length === 0) {
|
|
255
|
+
return { ok: false, error: "not_connected" };
|
|
256
|
+
}
|
|
257
|
+
const row = rows[0];
|
|
258
|
+
// Attempt remote revocation — best effort
|
|
259
|
+
try {
|
|
260
|
+
const { decryptField, aadFor, LookupKeyProvider } = await load_crypto_module();
|
|
261
|
+
const keys = makeKeyProvider(LookupKeyProvider);
|
|
262
|
+
const decrypted_refresh = await decryptField(JSON.parse(row.refresh_token_enc), {
|
|
263
|
+
keys,
|
|
264
|
+
aad: aadFor("hazo_google_oauth_tokens", userId, "refresh_token"),
|
|
265
|
+
});
|
|
266
|
+
const revoke_resp = await fetch(`https://oauth2.googleapis.com/revoke?token=${encodeURIComponent(decrypted_refresh)}`, { method: "POST" });
|
|
267
|
+
if (!revoke_resp.ok) {
|
|
268
|
+
logger.warn("google_token_service_revoke_remote_failed", {
|
|
269
|
+
filename: "google_token_service.ts",
|
|
270
|
+
user_id: userId,
|
|
271
|
+
status: revoke_resp.status,
|
|
272
|
+
note: "Google revocation returned non-OK status; proceeding to delete local record",
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
logger.info("google_token_service_revoke_remote_ok", {
|
|
277
|
+
filename: "google_token_service.ts",
|
|
278
|
+
user_id: userId,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
284
|
+
logger.warn("google_token_service_revoke_remote_error", {
|
|
285
|
+
filename: "google_token_service.ts",
|
|
286
|
+
user_id: userId,
|
|
287
|
+
error: msg,
|
|
288
|
+
note: "Remote revocation failed; proceeding to delete local record",
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
// Always delete the local row
|
|
292
|
+
await service.deleteById(row.id);
|
|
293
|
+
access_token_cache.delete(userId);
|
|
294
|
+
logger.info("google_token_service_revoked", {
|
|
295
|
+
filename: "google_token_service.ts",
|
|
296
|
+
user_id: userId,
|
|
297
|
+
});
|
|
298
|
+
return { ok: true };
|
|
299
|
+
}
|
|
300
|
+
// section: status
|
|
301
|
+
/**
|
|
302
|
+
* Returns connection status and scope information for a user's Google OAuth connection.
|
|
303
|
+
* Does not decrypt or refresh tokens.
|
|
304
|
+
*/
|
|
305
|
+
export async function get_google_token_status(userId) {
|
|
306
|
+
var _a;
|
|
307
|
+
const adapter = get_hazo_connect_instance();
|
|
308
|
+
const service = createCrudService(adapter, "hazo_google_oauth_tokens");
|
|
309
|
+
const rows = (await service.findBy({ user_id: userId, provider: "google" }));
|
|
310
|
+
if (rows.length === 0) {
|
|
311
|
+
return { connected: false, scopes: "", expires_at: null };
|
|
312
|
+
}
|
|
313
|
+
const row = rows[0];
|
|
314
|
+
return {
|
|
315
|
+
connected: true,
|
|
316
|
+
scopes: row.scopes,
|
|
317
|
+
expires_at: (_a = row.expires_at) !== null && _a !== void 0 ? _a : null,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
|
|
@@ -53,7 +53,7 @@ export declare function revoke_invitation(adapter: HazoConnectAdapter, invitatio
|
|
|
53
53
|
*/
|
|
54
54
|
export declare function list_invitations_by_scope(adapter: HazoConnectAdapter, scope_id: string, status?: InvitationStatus): Promise<InvitationServiceResult>;
|
|
55
55
|
/**
|
|
56
|
-
* Lists all invitations (for
|
|
56
|
+
* Lists all invitations (for global admins)
|
|
57
57
|
*/
|
|
58
58
|
export declare function list_all_invitations(adapter: HazoConnectAdapter, status?: InvitationStatus): Promise<InvitationServiceResult>;
|
|
59
59
|
/**
|
|
@@ -365,7 +365,7 @@ export async function list_invitations_by_scope(adapter, scope_id, status) {
|
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
/**
|
|
368
|
-
* Lists all invitations (for
|
|
368
|
+
* Lists all invitations (for global admins)
|
|
369
369
|
*/
|
|
370
370
|
export async function list_all_invitations(adapter, status) {
|
|
371
371
|
try {
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import type { HazoConnectAdapter } from "hazo_connect";
|
|
2
|
-
/**
|
|
3
|
-
* Super admin scope ID - special UUID for system-level administrators
|
|
4
|
-
* Users assigned to this scope have global access
|
|
5
|
-
*/
|
|
6
|
-
export declare const SUPER_ADMIN_SCOPE_ID = "00000000-0000-0000-0000-000000000000";
|
|
7
2
|
/**
|
|
8
3
|
* Default system scope ID - for non-multi-tenancy mode
|
|
9
4
|
* All users are assigned to this scope when multi-tenancy is disabled
|
|
@@ -67,16 +62,12 @@ export declare function extract_branding(scope: ScopeRecord): FirmBranding | nul
|
|
|
67
62
|
* Checks if a scope has any branding set
|
|
68
63
|
*/
|
|
69
64
|
export declare function has_branding(scope: ScopeRecord): boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Checks if the given scope_id is the super admin scope
|
|
72
|
-
*/
|
|
73
|
-
export declare function is_super_admin_scope(scope_id: string): boolean;
|
|
74
65
|
/**
|
|
75
66
|
* Checks if the given scope_id is the default system scope
|
|
76
67
|
*/
|
|
77
68
|
export declare function is_default_system_scope(scope_id: string): boolean;
|
|
78
69
|
/**
|
|
79
|
-
* Checks if the given scope_id is a system scope (
|
|
70
|
+
* Checks if the given scope_id is a system scope (default system)
|
|
80
71
|
*/
|
|
81
72
|
export declare function is_system_scope(scope_id: string): boolean;
|
|
82
73
|
/**
|
|
@@ -133,10 +124,6 @@ export declare function get_scope_tree(adapter: HazoConnectAdapter, root_scope_i
|
|
|
133
124
|
tree?: ScopeTreeNode[];
|
|
134
125
|
error?: string;
|
|
135
126
|
}>;
|
|
136
|
-
/**
|
|
137
|
-
* Ensures the super admin scope exists
|
|
138
|
-
*/
|
|
139
|
-
export declare function ensure_super_admin_scope(adapter: HazoConnectAdapter): Promise<ScopeServiceResult>;
|
|
140
127
|
/**
|
|
141
128
|
* Ensures the default system scope exists
|
|
142
129
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/scope_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOvD;;;GAGG;AACH,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/scope_service.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,6 @@ import { createCrudService } from "hazo_connect/server";
|
|
|
2
2
|
import { create_app_logger } from "../app_logger.js";
|
|
3
3
|
import { sanitize_error_for_user } from "../utils/error_sanitizer.js";
|
|
4
4
|
// section: constants
|
|
5
|
-
/**
|
|
6
|
-
* Super admin scope ID - special UUID for system-level administrators
|
|
7
|
-
* Users assigned to this scope have global access
|
|
8
|
-
*/
|
|
9
|
-
export const SUPER_ADMIN_SCOPE_ID = "00000000-0000-0000-0000-000000000000";
|
|
10
5
|
/**
|
|
11
6
|
* Default system scope ID - for non-multi-tenancy mode
|
|
12
7
|
* All users are assigned to this scope when multi-tenancy is disabled
|
|
@@ -52,12 +47,6 @@ export function extract_branding(scope) {
|
|
|
52
47
|
export function has_branding(scope) {
|
|
53
48
|
return !!(scope.logo_url || scope.primary_color || scope.secondary_color || scope.tagline);
|
|
54
49
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Checks if the given scope_id is the super admin scope
|
|
57
|
-
*/
|
|
58
|
-
export function is_super_admin_scope(scope_id) {
|
|
59
|
-
return scope_id === SUPER_ADMIN_SCOPE_ID;
|
|
60
|
-
}
|
|
61
50
|
/**
|
|
62
51
|
* Checks if the given scope_id is the default system scope
|
|
63
52
|
*/
|
|
@@ -65,10 +54,10 @@ export function is_default_system_scope(scope_id) {
|
|
|
65
54
|
return scope_id === DEFAULT_SYSTEM_SCOPE_ID;
|
|
66
55
|
}
|
|
67
56
|
/**
|
|
68
|
-
* Checks if the given scope_id is a system scope (
|
|
57
|
+
* Checks if the given scope_id is a system scope (default system)
|
|
69
58
|
*/
|
|
70
59
|
export function is_system_scope(scope_id) {
|
|
71
|
-
return
|
|
60
|
+
return is_default_system_scope(scope_id);
|
|
72
61
|
}
|
|
73
62
|
// section: crud operations
|
|
74
63
|
/**
|
|
@@ -605,60 +594,6 @@ export async function get_scope_tree(adapter, root_scope_id) {
|
|
|
605
594
|
};
|
|
606
595
|
}
|
|
607
596
|
}
|
|
608
|
-
/**
|
|
609
|
-
* Ensures the super admin scope exists
|
|
610
|
-
*/
|
|
611
|
-
export async function ensure_super_admin_scope(adapter) {
|
|
612
|
-
try {
|
|
613
|
-
// Check if already exists
|
|
614
|
-
const existing = await get_scope_by_id(adapter, SUPER_ADMIN_SCOPE_ID);
|
|
615
|
-
if (existing.success && existing.scope) {
|
|
616
|
-
return existing;
|
|
617
|
-
}
|
|
618
|
-
// Create it
|
|
619
|
-
const scope_service = createCrudService(adapter, "hazo_scopes");
|
|
620
|
-
const now = new Date().toISOString();
|
|
621
|
-
const inserted = await scope_service.insert({
|
|
622
|
-
id: SUPER_ADMIN_SCOPE_ID,
|
|
623
|
-
name: "Super Admin",
|
|
624
|
-
level: "system",
|
|
625
|
-
parent_id: null,
|
|
626
|
-
logo_url: null,
|
|
627
|
-
primary_color: null,
|
|
628
|
-
secondary_color: null,
|
|
629
|
-
tagline: null,
|
|
630
|
-
created_at: now,
|
|
631
|
-
changed_at: now,
|
|
632
|
-
});
|
|
633
|
-
if (!Array.isArray(inserted) || inserted.length === 0) {
|
|
634
|
-
return {
|
|
635
|
-
success: false,
|
|
636
|
-
error: "Failed to create super admin scope",
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
return {
|
|
640
|
-
success: true,
|
|
641
|
-
scope: normalize_scope_record(inserted[0]),
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
catch (error) {
|
|
645
|
-
const logger = create_app_logger();
|
|
646
|
-
const error_message = sanitize_error_for_user(error, {
|
|
647
|
-
logToConsole: true,
|
|
648
|
-
logToLogger: true,
|
|
649
|
-
logger,
|
|
650
|
-
context: {
|
|
651
|
-
filename: "scope_service.ts",
|
|
652
|
-
line_number: 0,
|
|
653
|
-
operation: "ensure_super_admin_scope",
|
|
654
|
-
},
|
|
655
|
-
});
|
|
656
|
-
return {
|
|
657
|
-
success: false,
|
|
658
|
-
error: error_message,
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
597
|
/**
|
|
663
598
|
* Ensures the default system scope exists
|
|
664
599
|
*/
|
|
@@ -20,7 +20,6 @@ export type ScopeAccessCheckResult = {
|
|
|
20
20
|
scope_name?: string;
|
|
21
21
|
};
|
|
22
22
|
user_scopes?: UserScope[];
|
|
23
|
-
is_super_admin?: boolean;
|
|
24
23
|
};
|
|
25
24
|
export type AssignUserScopeData = {
|
|
26
25
|
user_id: string;
|
|
@@ -52,10 +51,6 @@ export declare function update_user_scopes(adapter: HazoConnectAdapter, user_id:
|
|
|
52
51
|
scope_id: string;
|
|
53
52
|
role_id: string;
|
|
54
53
|
}>): Promise<UserScopeResult>;
|
|
55
|
-
/**
|
|
56
|
-
* Checks if a user is a super admin (has super admin scope assigned)
|
|
57
|
-
*/
|
|
58
|
-
export declare function is_user_super_admin(adapter: HazoConnectAdapter, user_id: string): Promise<boolean>;
|
|
59
54
|
/**
|
|
60
55
|
* Checks if a user has any scope assigned
|
|
61
56
|
*/
|
|
@@ -63,9 +58,11 @@ export declare function user_has_any_scope(adapter: HazoConnectAdapter, user_id:
|
|
|
63
58
|
/**
|
|
64
59
|
* Checks if a user has access to a specific scope
|
|
65
60
|
* Access is granted if:
|
|
66
|
-
* 1. User
|
|
67
|
-
* 2. User has
|
|
68
|
-
*
|
|
61
|
+
* 1. User has the exact scope assigned
|
|
62
|
+
* 2. User has access to an ancestor scope (inherited access)
|
|
63
|
+
*
|
|
64
|
+
* Global admin access (hazo_org_global_admin permission) is handled upstream
|
|
65
|
+
* in hazo_get_auth before this function is called.
|
|
69
66
|
*
|
|
70
67
|
* @param adapter - HazoConnect adapter
|
|
71
68
|
* @param user_id - User ID to check
|
|
@@ -85,8 +82,4 @@ export declare function get_user_direct_scopes(adapter: HazoConnectAdapter, user
|
|
|
85
82
|
}>;
|
|
86
83
|
error?: string;
|
|
87
84
|
}>;
|
|
88
|
-
/**
|
|
89
|
-
* Assigns super admin scope to a user
|
|
90
|
-
*/
|
|
91
|
-
export declare function assign_super_admin_scope(adapter: HazoConnectAdapter, user_id: string, role_id: string): Promise<UserScopeResult>;
|
|
92
85
|
//# sourceMappingURL=user_scope_service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user_scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/user_scope_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"user_scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/user_scope_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAuBvD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAIF;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,eAAe,CAAC,CA2E1B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CA2E1B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,OAAO,CAAC,eAAe,CAAC,CAwD1B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,sBAAsB,CAAC,CAoEjC;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA4CD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createCrudService } from "hazo_connect/server";
|
|
2
2
|
import { create_app_logger } from "../app_logger.js";
|
|
3
3
|
import { sanitize_error_for_user } from "../utils/error_sanitizer.js";
|
|
4
|
-
import { get_scope_by_id, get_scope_ancestors, get_root_scope_id,
|
|
4
|
+
import { get_scope_by_id, get_scope_ancestors, get_root_scope_id, } from "./scope_service.js";
|
|
5
5
|
// section: constants
|
|
6
6
|
/**
|
|
7
7
|
* CRUD service options for hazo_user_scopes table
|
|
@@ -274,21 +274,6 @@ export async function update_user_scopes(adapter, user_id, new_scopes) {
|
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
|
-
/**
|
|
278
|
-
* Checks if a user is a super admin (has super admin scope assigned)
|
|
279
|
-
*/
|
|
280
|
-
export async function is_user_super_admin(adapter, user_id) {
|
|
281
|
-
try {
|
|
282
|
-
const user_scopes_result = await get_user_scopes(adapter, user_id);
|
|
283
|
-
if (!user_scopes_result.success || !user_scopes_result.scopes) {
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
return user_scopes_result.scopes.some((scope) => is_super_admin_scope(scope.scope_id));
|
|
287
|
-
}
|
|
288
|
-
catch (_a) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
277
|
/**
|
|
293
278
|
* Checks if a user has any scope assigned
|
|
294
279
|
*/
|
|
@@ -306,9 +291,11 @@ export async function user_has_any_scope(adapter, user_id) {
|
|
|
306
291
|
/**
|
|
307
292
|
* Checks if a user has access to a specific scope
|
|
308
293
|
* Access is granted if:
|
|
309
|
-
* 1. User
|
|
310
|
-
* 2. User has
|
|
311
|
-
*
|
|
294
|
+
* 1. User has the exact scope assigned
|
|
295
|
+
* 2. User has access to an ancestor scope (inherited access)
|
|
296
|
+
*
|
|
297
|
+
* Global admin access (hazo_org_global_admin permission) is handled upstream
|
|
298
|
+
* in hazo_get_auth before this function is called.
|
|
312
299
|
*
|
|
313
300
|
* @param adapter - HazoConnect adapter
|
|
314
301
|
* @param user_id - User ID to check
|
|
@@ -323,20 +310,7 @@ export async function check_user_scope_access(adapter, user_id, target_scope_id)
|
|
|
323
310
|
return { has_access: false };
|
|
324
311
|
}
|
|
325
312
|
const user_scopes = user_scopes_result.scopes;
|
|
326
|
-
// Check 1:
|
|
327
|
-
const has_super_admin = user_scopes.some((scope) => is_super_admin_scope(scope.scope_id));
|
|
328
|
-
if (has_super_admin) {
|
|
329
|
-
return {
|
|
330
|
-
has_access: true,
|
|
331
|
-
access_via: {
|
|
332
|
-
scope_id: SUPER_ADMIN_SCOPE_ID,
|
|
333
|
-
scope_name: "Super Admin",
|
|
334
|
-
},
|
|
335
|
-
user_scopes,
|
|
336
|
-
is_super_admin: true,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
// Check 2: Does user have exact scope assigned?
|
|
313
|
+
// Check 1: Does user have exact scope assigned?
|
|
340
314
|
for (const user_scope of user_scopes) {
|
|
341
315
|
if (user_scope.scope_id === target_scope_id) {
|
|
342
316
|
const scope_result = await get_scope_by_id(adapter, target_scope_id);
|
|
@@ -352,7 +326,7 @@ export async function check_user_scope_access(adapter, user_id, target_scope_id)
|
|
|
352
326
|
};
|
|
353
327
|
}
|
|
354
328
|
}
|
|
355
|
-
// Check
|
|
329
|
+
// Check 2: Does user have access via an ancestor scope?
|
|
356
330
|
const ancestors_result = await get_scope_ancestors(adapter, target_scope_id);
|
|
357
331
|
if (ancestors_result.success && ancestors_result.scopes) {
|
|
358
332
|
for (const ancestor of ancestors_result.scopes) {
|
|
@@ -436,14 +410,3 @@ export async function get_user_direct_scopes(adapter, user_id) {
|
|
|
436
410
|
};
|
|
437
411
|
}
|
|
438
412
|
}
|
|
439
|
-
/**
|
|
440
|
-
* Assigns super admin scope to a user
|
|
441
|
-
*/
|
|
442
|
-
export async function assign_super_admin_scope(adapter, user_id, role_id) {
|
|
443
|
-
return assign_user_scope(adapter, {
|
|
444
|
-
user_id,
|
|
445
|
-
scope_id: SUPER_ADMIN_SCOPE_ID,
|
|
446
|
-
root_scope_id: SUPER_ADMIN_SCOPE_ID,
|
|
447
|
-
role_id,
|
|
448
|
-
});
|
|
449
|
-
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { NextRequest } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/hazo_auth/google/token
|
|
4
|
+
* Returns the current Google OAuth token status for the authenticated user.
|
|
5
|
+
*/
|
|
6
|
+
export declare function GET(request: NextRequest): Promise<Response>;
|
|
7
|
+
/**
|
|
8
|
+
* DELETE /api/hazo_auth/google/token
|
|
9
|
+
* Revokes the stored Google OAuth token for the authenticated user.
|
|
10
|
+
* Does NOT sign the user out.
|
|
11
|
+
*/
|
|
12
|
+
export declare function DELETE(request: NextRequest): Promise<Response>;
|
|
13
|
+
//# sourceMappingURL=google_token.d.ts.map
|