letopis 1.4.1 → 2.0.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/AGENT-CHEATSHEET.md +329 -278
- package/CHANGELOG.md +558 -1
- package/README.md +606 -1037
- package/dist/acl.d.ts +78 -1
- package/dist/acl.js +264 -13
- package/dist/admin.d.ts +10 -141
- package/dist/admin.js +24 -175
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +5 -15
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +33 -10
- package/dist/chain.d.ts +19 -41
- package/dist/chain.js +169 -201
- package/dist/cli.js +51 -88
- package/dist/demo/booking.d.ts +352 -36
- package/dist/describe.d.ts +47 -0
- package/dist/describe.js +195 -0
- package/dist/errors.d.ts +59 -13
- package/dist/errors.js +190 -29
- package/dist/index.d.ts +52 -71
- package/dist/index.js +245 -130
- package/dist/internal.d.ts +12 -0
- package/dist/internal.js +5 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +20 -12
- package/dist/load.js +225 -186
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +171 -215
- package/dist/messages/access.d.ts +90 -0
- package/dist/messages/access.js +113 -0
- package/dist/messages/api.d.ts +171 -0
- package/dist/messages/api.js +215 -0
- package/dist/messages/boot.d.ts +201 -0
- package/dist/messages/boot.js +256 -0
- package/dist/messages/codes.d.ts +172 -0
- package/dist/messages/codes.js +173 -0
- package/dist/messages/index.d.ts +95 -0
- package/dist/messages/index.js +118 -0
- package/dist/messages/mcp.d.ts +306 -0
- package/dist/messages/mcp.js +387 -0
- package/dist/messages/model.d.ts +233 -0
- package/dist/messages/model.js +283 -0
- package/dist/messages/query.d.ts +131 -0
- package/dist/messages/query.js +158 -0
- package/dist/messages/sql-access.d.ts +70 -0
- package/dist/messages/sql-access.js +87 -0
- package/dist/messages/sql-core.d.ts +150 -0
- package/dist/messages/sql-core.js +181 -0
- package/dist/messages/sql-time.d.ts +71 -0
- package/dist/messages/sql-time.js +88 -0
- package/dist/messages/sql-write.d.ts +246 -0
- package/dist/messages/sql-write.js +270 -0
- package/dist/messages/time.d.ts +23 -0
- package/dist/messages/time.js +29 -0
- package/dist/messages/types.d.ts +27 -0
- package/dist/messages/types.js +5 -0
- package/dist/messages/write.d.ts +405 -0
- package/dist/messages/write.js +509 -0
- package/dist/model.d.ts +73 -60
- package/dist/model.js +26 -29
- package/dist/ops.d.ts +35 -0
- package/dist/ops.js +101 -0
- package/dist/pglite.d.ts +0 -9
- package/dist/pglite.js +3 -1
- package/dist/registry.d.ts +3 -19
- package/dist/registry.js +3 -16
- package/dist/signals.d.ts +5 -9
- package/dist/signals.js +5 -9
- package/dist/sql.d.ts +13 -6
- package/dist/sql.js +176 -83
- package/dist/sync.d.ts +9 -3
- package/dist/sync.js +51 -21
- package/dist/tx.d.ts +26 -1
- package/dist/tx.js +44 -14
- package/dist/typed.d.ts +240 -45
- package/dist/types.d.ts +23 -91
- package/dist/types.js +12 -14
- package/dist/up.d.ts +53 -32
- package/dist/up.js +184 -73
- package/dist/uuid.js +5 -5
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +61 -29
- package/dist/watch.d.ts +11 -10
- package/dist/watch.js +33 -70
- package/dist/write.d.ts +9 -16
- package/dist/write.js +118 -187
- package/llms.txt +22 -25
- package/package.json +8 -11
- package/sql/10-core.sql +7 -50
- package/sql/15-errors.sql +64 -10
- package/sql/20-context.sql +7 -6
- package/sql/30-validate.sql +35 -27
- package/sql/40-class.sql +20 -114
- package/sql/50-acl.sql +8 -13
- package/sql/60-write.sql +220 -667
- package/sql/70-read.sql +20 -16
- package/sql/80-auth.sql +24 -27
- package/sql/90-time.sql +70 -859
- package/sql/95-seed.system.sql +7 -14
- package/sql/99-revision.sql +2 -1
- package/sql/README.md +32 -24
- package/sql/migrate/README.md +14 -0
- package/AGENT-CHEATSHEET.en.md +0 -485
- package/MIGRATION.md +0 -190
- package/README.en.md +0 -2859
- package/dist/import.d.ts +0 -185
- package/dist/import.js +0 -820
- package/dist/project.d.ts +0 -350
- package/dist/project.js +0 -1224
- package/sql/75-history.sql +0 -358
- package/sql/88-derived.sql +0 -1235
- package/sql/migrate/0006-changed-paths.sql +0 -3
- package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/sql/70-read.sql
CHANGED
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
--
|
|
18
18
|
-- Источник — текущее состояние (entity) или журнал: версии, действовавшие на момент p_at (срез
|
|
19
19
|
-- asOf), либо надгробия удалённых (p_dead, для withDeleted). Возвращается rev версии: строки
|
|
20
|
-
-- журнала читаются по паре (id, rev) через уникальный индекс log_id_rev.
|
|
21
|
-
-- (этап 6) — не версии объекта: на момент после них объекта в срезе нет.
|
|
20
|
+
-- журнала читаются по паре (id, rev) через уникальный индекс log_id_rev.
|
|
22
21
|
|
|
23
22
|
-- Цели концов строки: всех (p_roles is null) или только перечисленных ролей.
|
|
24
23
|
create or replace function @SCHEMA@.role_ids(p_links jsonb, p_roles text[]) returns uuid[]
|
|
@@ -53,9 +52,10 @@ as $$
|
|
|
53
52
|
where r.class = any (p_classes) and r.at <= coalesce(p_at, 'infinity'::timestamptz)) c
|
|
54
53
|
cross join lateral (
|
|
55
54
|
select y.* from (select x.* from @SCHEMA@.log x where x.id = c.id offset 0) y
|
|
56
|
-
where y.
|
|
55
|
+
where y.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
57
56
|
order by y.rev desc limit 1) w
|
|
58
|
-
|
|
57
|
+
-- класс — у последней версии на момент, а не среди версий классов шага (план 2.0, 7.1 №1)
|
|
58
|
+
where w.class = any (p_classes) and @SCHEMA@.link_ids(w.links) @> array[p_src]
|
|
59
59
|
$$;
|
|
60
60
|
|
|
61
61
|
-- id строк классов p_classes: по вложению в data (GIN entity_data), по целям концов (GIN entity_ends),
|
|
@@ -121,32 +121,36 @@ begin
|
|
|
121
121
|
from @SCHEMA@.log l
|
|
122
122
|
where l.id = any (p_ids) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
123
123
|
order by l.id, l.rev desc) v
|
|
124
|
-
where v.class = any (p_classes) and (v.op = 'delete') = p_dead
|
|
124
|
+
where v.class = any (p_classes) and (v.op = 'delete') = p_dead
|
|
125
125
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
126
126
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
|
|
127
127
|
elsif p_ends is not null then
|
|
128
128
|
-- по целям концов — от версий, ссылавшихся на первую цель (GIN log_ends); арендатор — после пробы
|
|
129
129
|
return query select v.id, v.rev from @SCHEMA@.log_refs_at(p_classes, p_ends[1], p_at) v
|
|
130
130
|
where (v.tenant = any (v_tenants) or v.class = 'member')
|
|
131
|
-
and (v.op = 'delete') = p_dead
|
|
131
|
+
and (v.op = 'delete') = p_dead
|
|
132
132
|
and (p_data is null or v.data @> p_data) and @SCHEMA@.link_ids(v.links) @> p_ends
|
|
133
133
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
|
|
134
134
|
else
|
|
135
|
-
-- арендатор id
|
|
135
|
+
-- арендатор id неизменен: условие до distinct on не меняет, какая
|
|
136
136
|
-- версия id последняя (индекс log_class_tenant_at)
|
|
137
|
+
-- кандидаты — по классу (индекс log_class_tenant_at), последняя версия id на момент — любого класса, и класс
|
|
138
|
+
-- проверяется у неё (план 2.0, 7.1 №1)
|
|
137
139
|
return query select v.id, v.rev from (
|
|
138
|
-
select distinct
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
select distinct l.id from @SCHEMA@.log l
|
|
141
|
+
where l.class = any (p_classes) and l.tenant = any (v_tenants) and l.at <= coalesce(p_at, 'infinity'::timestamptz)) c
|
|
142
|
+
cross join lateral (
|
|
143
|
+
select y.id, y.rev, y.op, y.class, y.tenant, y.owner, y.tags, y.data, y.links
|
|
144
|
+
from @SCHEMA@.log y where y.id = c.id and y.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
145
|
+
order by y.rev desc limit 1) v
|
|
146
|
+
where v.class = any (p_classes) and (v.op = 'delete') = p_dead
|
|
143
147
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
144
148
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
|
|
145
149
|
-- свои членства в других арендаторах: версии, ссылавшиеся на аккаунт (GIN log_ends)
|
|
146
150
|
if v_member then
|
|
147
151
|
return query select v.id, v.rev from @SCHEMA@.log_refs_at(array['member'], c_account, p_at) v
|
|
148
152
|
where not (v.tenant = any (v_tenants))
|
|
149
|
-
and (v.op = 'delete') = p_dead
|
|
153
|
+
and (v.op = 'delete') = p_dead
|
|
150
154
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
151
155
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
|
|
152
156
|
end if;
|
|
@@ -187,7 +191,7 @@ begin
|
|
|
187
191
|
return query select s.src, v.id, v.rev
|
|
188
192
|
from (select distinct u.x as src from unnest(p_src) u(x)) s
|
|
189
193
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
|
|
190
|
-
where (v.op = 'delete') = p_dead
|
|
194
|
+
where (v.op = 'delete') = p_dead
|
|
191
195
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
192
196
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
|
|
193
197
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
|
|
@@ -237,14 +241,14 @@ begin
|
|
|
237
241
|
select s.src, v.id, v.rev, 1, array[s.src, v.id]
|
|
238
242
|
from (select distinct u.x as src from unnest(p_src) u(x)) s
|
|
239
243
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
|
|
240
|
-
where v.op
|
|
244
|
+
where v.op <> 'delete'
|
|
241
245
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
|
|
242
246
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan)
|
|
243
247
|
union all
|
|
244
248
|
select d.src, v.id, v.rev, d.depth + 1, d.seen || v.id
|
|
245
249
|
from d
|
|
246
250
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, d.id, p_at) v
|
|
247
|
-
where d.depth < p_max and not (v.id = any (d.seen)) and v.op
|
|
251
|
+
where d.depth < p_max and not (v.id = any (d.seen)) and v.op <> 'delete'
|
|
248
252
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, d.id))
|
|
249
253
|
and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan))
|
|
250
254
|
select distinct on (d.src, d.id) d.src, d.id, d.rev, d.depth from d order by d.src, d.id, d.depth;
|
package/sql/80-auth.sql
CHANGED
|
@@ -17,7 +17,7 @@ return interval '10 minutes';
|
|
|
17
17
|
|
|
18
18
|
create or replace function @SCHEMA@.auth_kind_ok(p_kind text) returns boolean
|
|
19
19
|
language sql immutable parallel safe
|
|
20
|
-
return p_kind ~ '^[A-Z][A-Z0-9_]{1,31}$' and p_kind not in ('SESSION', 'APIKEY', 'KEYSECRET', 'OTP', 'TOTP', 'KEY', '
|
|
20
|
+
return p_kind ~ '^[A-Z][A-Z0-9_]{1,31}$' and p_kind not in ('SESSION', 'APIKEY', 'KEYSECRET', 'OTP', 'TOTP', 'KEY', 'LOCK');
|
|
21
21
|
|
|
22
22
|
-- Действующая сессия обязательна (иначе no_session).
|
|
23
23
|
create or replace function @SCHEMA@.auth_session_required(p_account uuid) returns void
|
|
@@ -25,7 +25,7 @@ language plpgsql immutable
|
|
|
25
25
|
as $$
|
|
26
26
|
begin
|
|
27
27
|
if p_account is null then
|
|
28
|
-
perform @SCHEMA@.lt_fail('no_session'
|
|
28
|
+
perform @SCHEMA@.lt_fail('sql-access.no_session');
|
|
29
29
|
end if;
|
|
30
30
|
end $$;
|
|
31
31
|
|
|
@@ -42,7 +42,7 @@ declare
|
|
|
42
42
|
begin
|
|
43
43
|
select * into c from @SCHEMA@.ctx();
|
|
44
44
|
if c.account is null then
|
|
45
|
-
perform @SCHEMA@.lt_fail('no_session'
|
|
45
|
+
perform @SCHEMA@.lt_fail('sql-access.no_session');
|
|
46
46
|
end if;
|
|
47
47
|
if c.account = p_account and c.service is null then
|
|
48
48
|
select (s.meta->>'login_at')::timestamptz, coalesce(s.meta->'methods', '[]'::jsonb) into login_at, methods
|
|
@@ -57,12 +57,12 @@ begin
|
|
|
57
57
|
end if;
|
|
58
58
|
end if;
|
|
59
59
|
if not coalesce((@SCHEMA@.acl_api_for(c.tenant, c.categories, c.roles, 'auth.credential', true)->>'allow')::boolean, false) then
|
|
60
|
-
perform @SCHEMA@.lt_fail('
|
|
60
|
+
perform @SCHEMA@.lt_fail('sql-access.bind_denied');
|
|
61
61
|
end if;
|
|
62
62
|
-- креды System, сервисов и системных администраторов выдаёт только системный администратор: иначе
|
|
63
63
|
-- сервис привязал бы себе вход под ними (ревью этапа 5)
|
|
64
64
|
if not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
|
|
65
|
-
perform @SCHEMA@.lt_fail('
|
|
65
|
+
perform @SCHEMA@.lt_fail('sql-access.bind_denied');
|
|
66
66
|
end if;
|
|
67
67
|
end $$;
|
|
68
68
|
|
|
@@ -77,7 +77,7 @@ declare
|
|
|
77
77
|
begin
|
|
78
78
|
select * into c from @SCHEMA@.ctx();
|
|
79
79
|
if p_account is distinct from c.account and not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
|
|
80
|
-
perform @SCHEMA@.lt_fail('
|
|
80
|
+
perform @SCHEMA@.lt_fail('sql-access.self_or_sysadmin');
|
|
81
81
|
end if;
|
|
82
82
|
end $$;
|
|
83
83
|
|
|
@@ -203,7 +203,7 @@ begin
|
|
|
203
203
|
perform @SCHEMA@.auth_session_required(c.account);
|
|
204
204
|
perform @SCHEMA@.acl_require('auth.session');
|
|
205
205
|
if not @SCHEMA@.auth_target_ok(p_account) then
|
|
206
|
-
perform @SCHEMA@.lt_fail('
|
|
206
|
+
perform @SCHEMA@.lt_fail('sql-access.no_sessions_for_account');
|
|
207
207
|
end if;
|
|
208
208
|
return @SCHEMA@.new_session(p_account, p_ttl, jsonb_build_object('methods', to_jsonb(p_methods), 'service', c.account));
|
|
209
209
|
end $$;
|
|
@@ -248,14 +248,14 @@ begin
|
|
|
248
248
|
p_confirmed := null;
|
|
249
249
|
end if;
|
|
250
250
|
if not @SCHEMA@.auth_kind_ok(p_kind) or coalesce(p_ident, '') = '' or p_hash !~ '^scrypt\$' then
|
|
251
|
-
perform @SCHEMA@.lt_fail('
|
|
251
|
+
perform @SCHEMA@.lt_fail('sql-access.password_args');
|
|
252
252
|
end if;
|
|
253
253
|
select s.id, s.account into cur from @SCHEMA@.secret s
|
|
254
254
|
where s.kind = p_kind and s.deleted_at is null
|
|
255
255
|
and casefold(s.ident) collate pg_unicode_fast = casefold(p_ident) collate pg_unicode_fast
|
|
256
256
|
for update;
|
|
257
257
|
if cur.id is not null and cur.account <> p_account then
|
|
258
|
-
perform @SCHEMA@.lt_fail('
|
|
258
|
+
perform @SCHEMA@.lt_fail('sql-access.bind_denied');
|
|
259
259
|
end if;
|
|
260
260
|
if cur.id is not null then
|
|
261
261
|
update @SCHEMA@.secret s
|
|
@@ -270,7 +270,7 @@ begin
|
|
|
270
270
|
values (p_account, p_kind, p_ident, convert_to(p_hash, 'UTF8'), jsonb_build_object('confirmed', coalesce(p_confirmed, false)))
|
|
271
271
|
returning id into cid;
|
|
272
272
|
exception when unique_violation then
|
|
273
|
-
perform @SCHEMA@.lt_fail('
|
|
273
|
+
perform @SCHEMA@.lt_fail('sql-access.bind_denied');
|
|
274
274
|
end;
|
|
275
275
|
end if;
|
|
276
276
|
return cid;
|
|
@@ -308,7 +308,7 @@ begin
|
|
|
308
308
|
null; -- совпал префикс: новый ключ
|
|
309
309
|
end;
|
|
310
310
|
end loop;
|
|
311
|
-
perform @SCHEMA@.lt_raise('40001',
|
|
311
|
+
perform @SCHEMA@.lt_raise('40001','sql-access.apikey_prefix_conflict', '{}'::jsonb);
|
|
312
312
|
end $$;
|
|
313
313
|
|
|
314
314
|
-- Вход по ключу API для db.auth.verifyApiKey: { account, token } или null (login_apikey — для
|
|
@@ -390,13 +390,13 @@ declare
|
|
|
390
390
|
begin
|
|
391
391
|
perform @SCHEMA@.acl_require('auth.otp');
|
|
392
392
|
if p_kind !~ '^OTP(_[A-Z0-9]{1,27})?$' or coalesce(p_ident, '') = '' or p_digits not between 4 and 10 then
|
|
393
|
-
perform @SCHEMA@.lt_fail('
|
|
393
|
+
perform @SCHEMA@.lt_fail('sql-access.otp_args');
|
|
394
394
|
end if;
|
|
395
395
|
if not @SCHEMA@.auth_enabled(p_account) then
|
|
396
|
-
perform @SCHEMA@.lt_fail('
|
|
396
|
+
perform @SCHEMA@.lt_fail('sql-access.account_not_found');
|
|
397
397
|
end if;
|
|
398
398
|
if not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
|
|
399
|
-
perform @SCHEMA@.lt_fail('
|
|
399
|
+
perform @SCHEMA@.lt_fail('sql-access.otp_sysadmin_only');
|
|
400
400
|
end if;
|
|
401
401
|
code := lpad((('x' || encode(@PGCRYPTO@.gen_random_bytes(7), 'hex'))::bit(56)::bigint % (10::bigint ^ p_digits)::bigint)::text, p_digits, '0');
|
|
402
402
|
update @SCHEMA@.secret s set deleted_at = clock_timestamp()
|
|
@@ -564,7 +564,7 @@ begin
|
|
|
564
564
|
p_confirmed := false;
|
|
565
565
|
end if;
|
|
566
566
|
if not @SCHEMA@.auth_kind_ok(p_kind) or p_kind = 'PASSWORD' or coalesce(p_ident, '') = '' then
|
|
567
|
-
perform @SCHEMA@.lt_fail('
|
|
567
|
+
perform @SCHEMA@.lt_fail('sql-access.identity_args');
|
|
568
568
|
end if;
|
|
569
569
|
begin
|
|
570
570
|
insert into @SCHEMA@.secret (account, kind, ident, meta)
|
|
@@ -572,7 +572,7 @@ begin
|
|
|
572
572
|
|| jsonb_build_object('confirmed', coalesce(p_confirmed, false)))
|
|
573
573
|
returning id into cid;
|
|
574
574
|
exception when unique_violation then
|
|
575
|
-
perform @SCHEMA@.lt_fail('
|
|
575
|
+
perform @SCHEMA@.lt_fail('sql-access.bind_denied');
|
|
576
576
|
end;
|
|
577
577
|
return cid;
|
|
578
578
|
end $$;
|
|
@@ -617,7 +617,7 @@ begin
|
|
|
617
617
|
coalesce((s.meta->>'confirmed')::boolean, false), coalesce((s.meta->>'enabled')::boolean, true),
|
|
618
618
|
s.meta - 'confirmed' - 'enabled' - 'attempts' - 'last_step', s.created_at, s.expires_at
|
|
619
619
|
from @SCHEMA@.secret s
|
|
620
|
-
where s.account = p_account and s.kind not in ('SESSION', 'KEY', '
|
|
620
|
+
where s.account = p_account and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null
|
|
621
621
|
and (s.expires_at is null or s.expires_at > clock_timestamp())
|
|
622
622
|
order by s.created_at, s.id;
|
|
623
623
|
end $$;
|
|
@@ -639,7 +639,7 @@ begin
|
|
|
639
639
|
perform @SCHEMA@.auth_session_required(c.account);
|
|
640
640
|
select s.account, s.kind,
|
|
641
641
|
(s.expires_at is null or s.expires_at > clock_timestamp()) and coalesce((s.meta->>'enabled')::boolean, true) as live
|
|
642
|
-
into cr from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', '
|
|
642
|
+
into cr from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null;
|
|
643
643
|
if cr.account is null then
|
|
644
644
|
return false;
|
|
645
645
|
end if;
|
|
@@ -655,7 +655,7 @@ begin
|
|
|
655
655
|
if not exists (select 1 from @SCHEMA@.secret s
|
|
656
656
|
where s.account = cr.account and s.kind in ('APIKEY', 'KEYSECRET') and s.deleted_at is null and s.id <> p_id
|
|
657
657
|
and (s.expires_at is null or s.expires_at > clock_timestamp()) and coalesce((s.meta->>'enabled')::boolean, true)) then
|
|
658
|
-
perform @SCHEMA@.lt_fail('
|
|
658
|
+
perform @SCHEMA@.lt_fail('sql-access.last_service_key');
|
|
659
659
|
end if;
|
|
660
660
|
end if;
|
|
661
661
|
update @SCHEMA@.secret s set deleted_at = clock_timestamp() where s.id = p_id and s.deleted_at is null;
|
|
@@ -679,7 +679,7 @@ declare
|
|
|
679
679
|
acc uuid;
|
|
680
680
|
begin
|
|
681
681
|
perform @SCHEMA@.acl_require('auth.credential');
|
|
682
|
-
select s.account into acc from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', '
|
|
682
|
+
select s.account into acc from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null;
|
|
683
683
|
if acc is null then
|
|
684
684
|
return false;
|
|
685
685
|
end if;
|
|
@@ -755,20 +755,21 @@ declare
|
|
|
755
755
|
s record;
|
|
756
756
|
begin
|
|
757
757
|
if nullif(current_setting('letopis.account', true), '') is not null then
|
|
758
|
-
|
|
758
|
+
-- код из каталога базы (invalid_query в нём нет — lt_fail дал бы LT000 и сырую ошибку; план 2.0, 7.5 №3)
|
|
759
|
+
perform @SCHEMA@.lt_fail('sql-access.switch_impersonating');
|
|
759
760
|
end if;
|
|
760
761
|
select x.id, x.account into s from @SCHEMA@.secret x
|
|
761
762
|
where x.kind = 'SESSION' and x.deleted_at is null and x.material = sha256(convert_to(coalesce(tok, ''), 'UTF8'))
|
|
762
763
|
and (x.expires_at is null or x.expires_at > clock_timestamp())
|
|
763
764
|
for update;
|
|
764
765
|
if s.id is null or not @SCHEMA@.auth_enabled(s.account) then
|
|
765
|
-
perform @SCHEMA@.lt_fail('no_session'
|
|
766
|
+
perform @SCHEMA@.lt_fail('sql-access.no_session');
|
|
766
767
|
end if;
|
|
767
768
|
if p_tenant <> s.account and not (
|
|
768
769
|
exists (select 1 from @SCHEMA@.entity x
|
|
769
770
|
where x.id = @SCHEMA@.v5_id(p_tenant, 'member', array[s.account::text, p_tenant::text]) and x.class = 'member' and x.tenant = p_tenant)
|
|
770
771
|
and @SCHEMA@.auth_enabled(p_tenant)) then
|
|
771
|
-
perform @SCHEMA@.lt_fail('
|
|
772
|
+
perform @SCHEMA@.lt_fail('sql-access.no_membership');
|
|
772
773
|
end if;
|
|
773
774
|
update @SCHEMA@.secret x
|
|
774
775
|
set meta = case when p_tenant = s.account then x.meta - 'tenant' else x.meta || jsonb_build_object('tenant', p_tenant) end
|
|
@@ -849,10 +850,6 @@ begin
|
|
|
849
850
|
execute format('revoke all on function @SCHEMA@.%s from public', f);
|
|
850
851
|
end loop;
|
|
851
852
|
end $$;
|
|
852
|
-
-- до этапа 5 выпуск сессии сервисом принимал два аргумента; ранние сигнатуры OTP этапа 5
|
|
853
|
-
drop function if exists @SCHEMA@.issue_session(uuid, interval);
|
|
854
|
-
drop function if exists @SCHEMA@.auth_issue_otp(uuid, text, text, interval, int);
|
|
855
|
-
drop function if exists @SCHEMA@.login_otp(text, text, text, int);
|
|
856
853
|
grant execute on function
|
|
857
854
|
@SCHEMA@.issue_session(uuid, interval, text[]), @SCHEMA@.auth_password_get(text, text),
|
|
858
855
|
@SCHEMA@.auth_set_password(uuid, text, text, text, boolean, boolean), @SCHEMA@.auth_issue_apikey(uuid, text, interval),
|