letopis 1.4.2 → 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 -281
- package/CHANGELOG.md +418 -0
- package/README.md +572 -1053
- 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 -184
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +5 -15
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +30 -8
- package/dist/chain.d.ts +18 -41
- package/dist/chain.js +165 -203
- package/dist/cli.js +45 -90
- 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 -70
- package/dist/index.js +189 -122
- package/dist/internal.d.ts +5 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +20 -12
- package/dist/load.js +207 -181
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +168 -214
- 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 +20 -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 +1 -5
- package/dist/signals.js +1 -5
- package/dist/sql.d.ts +7 -1
- package/dist/sql.js +101 -85
- package/dist/sync.d.ts +9 -3
- package/dist/sync.js +40 -17
- package/dist/tx.d.ts +11 -1
- package/dist/tx.js +32 -11
- package/dist/typed.d.ts +240 -45
- package/dist/types.d.ts +15 -90
- package/dist/types.js +12 -14
- package/dist/up.d.ts +53 -32
- package/dist/up.js +180 -74
- package/dist/uuid.js +5 -5
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +61 -29
- package/dist/watch.d.ts +5 -16
- package/dist/watch.js +23 -77
- package/dist/write.d.ts +9 -16
- package/dist/write.js +102 -185
- package/llms.txt +22 -25
- package/package.json +2 -9
- 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 -676
- package/sql/70-read.sql +11 -13
- package/sql/80-auth.sql +23 -27
- package/sql/90-time.sql +77 -944
- 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 -488
- package/MIGRATION.md +0 -190
- package/README.en.md +0 -2910
- package/dist/import.d.ts +0 -185
- package/dist/import.js +0 -820
- package/dist/project.d.ts +0 -359
- package/dist/project.js +0 -1258
- package/sql/75-history.sql +0 -436
- package/sql/88-derived.sql +0 -1236
- 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[]
|
|
@@ -55,8 +54,7 @@ as $$
|
|
|
55
54
|
select y.* from (select x.* from @SCHEMA@.log x where x.id = c.id offset 0) y
|
|
56
55
|
where y.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
57
56
|
order by y.rev desc limit 1) w
|
|
58
|
-
-- класс — у последней версии на момент, а не среди версий классов
|
|
59
|
-
-- не числится в прежнем классе (план 2.0, 7.1 №1)
|
|
57
|
+
-- класс — у последней версии на момент, а не среди версий классов шага (план 2.0, 7.1 №1)
|
|
60
58
|
where w.class = any (p_classes) and @SCHEMA@.link_ids(w.links) @> array[p_src]
|
|
61
59
|
$$;
|
|
62
60
|
|
|
@@ -123,21 +121,21 @@ begin
|
|
|
123
121
|
from @SCHEMA@.log l
|
|
124
122
|
where l.id = any (p_ids) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
125
123
|
order by l.id, l.rev desc) v
|
|
126
|
-
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
|
|
127
125
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
128
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);
|
|
129
127
|
elsif p_ends is not null then
|
|
130
128
|
-- по целям концов — от версий, ссылавшихся на первую цель (GIN log_ends); арендатор — после пробы
|
|
131
129
|
return query select v.id, v.rev from @SCHEMA@.log_refs_at(p_classes, p_ends[1], p_at) v
|
|
132
130
|
where (v.tenant = any (v_tenants) or v.class = 'member')
|
|
133
|
-
and (v.op = 'delete') = p_dead
|
|
131
|
+
and (v.op = 'delete') = p_dead
|
|
134
132
|
and (p_data is null or v.data @> p_data) and @SCHEMA@.link_ids(v.links) @> p_ends
|
|
135
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);
|
|
136
134
|
else
|
|
137
|
-
-- арендатор id
|
|
135
|
+
-- арендатор id неизменен: условие до distinct on не меняет, какая
|
|
138
136
|
-- версия id последняя (индекс log_class_tenant_at)
|
|
139
137
|
-- кандидаты — по классу (индекс log_class_tenant_at), последняя версия id на момент — любого класса, и класс
|
|
140
|
-
-- проверяется у
|
|
138
|
+
-- проверяется у неё (план 2.0, 7.1 №1)
|
|
141
139
|
return query select v.id, v.rev from (
|
|
142
140
|
select distinct l.id from @SCHEMA@.log l
|
|
143
141
|
where l.class = any (p_classes) and l.tenant = any (v_tenants) and l.at <= coalesce(p_at, 'infinity'::timestamptz)) c
|
|
@@ -145,14 +143,14 @@ begin
|
|
|
145
143
|
select y.id, y.rev, y.op, y.class, y.tenant, y.owner, y.tags, y.data, y.links
|
|
146
144
|
from @SCHEMA@.log y where y.id = c.id and y.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
147
145
|
order by y.rev desc limit 1) v
|
|
148
|
-
where v.class = any (p_classes) and (v.op = 'delete') = p_dead
|
|
146
|
+
where v.class = any (p_classes) and (v.op = 'delete') = p_dead
|
|
149
147
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
150
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);
|
|
151
149
|
-- свои членства в других арендаторах: версии, ссылавшиеся на аккаунт (GIN log_ends)
|
|
152
150
|
if v_member then
|
|
153
151
|
return query select v.id, v.rev from @SCHEMA@.log_refs_at(array['member'], c_account, p_at) v
|
|
154
152
|
where not (v.tenant = any (v_tenants))
|
|
155
|
-
and (v.op = 'delete') = p_dead
|
|
153
|
+
and (v.op = 'delete') = p_dead
|
|
156
154
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
157
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);
|
|
158
156
|
end if;
|
|
@@ -193,7 +191,7 @@ begin
|
|
|
193
191
|
return query select s.src, v.id, v.rev
|
|
194
192
|
from (select distinct u.x as src from unnest(p_src) u(x)) s
|
|
195
193
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
|
|
196
|
-
where (v.op = 'delete') = p_dead
|
|
194
|
+
where (v.op = 'delete') = p_dead
|
|
197
195
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
198
196
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
|
|
199
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);
|
|
@@ -243,14 +241,14 @@ begin
|
|
|
243
241
|
select s.src, v.id, v.rev, 1, array[s.src, v.id]
|
|
244
242
|
from (select distinct u.x as src from unnest(p_src) u(x)) s
|
|
245
243
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
|
|
246
|
-
where v.op
|
|
244
|
+
where v.op <> 'delete'
|
|
247
245
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
|
|
248
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)
|
|
249
247
|
union all
|
|
250
248
|
select d.src, v.id, v.rev, d.depth + 1, d.seen || v.id
|
|
251
249
|
from d
|
|
252
250
|
cross join lateral @SCHEMA@.log_refs_at(p_classes, d.id, p_at) v
|
|
253
|
-
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'
|
|
254
252
|
and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, d.id))
|
|
255
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))
|
|
256
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;
|
|
@@ -756,20 +756,20 @@ declare
|
|
|
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('
|
|
759
|
+
perform @SCHEMA@.lt_fail('sql-access.switch_impersonating');
|
|
760
760
|
end if;
|
|
761
761
|
select x.id, x.account into s from @SCHEMA@.secret x
|
|
762
762
|
where x.kind = 'SESSION' and x.deleted_at is null and x.material = sha256(convert_to(coalesce(tok, ''), 'UTF8'))
|
|
763
763
|
and (x.expires_at is null or x.expires_at > clock_timestamp())
|
|
764
764
|
for update;
|
|
765
765
|
if s.id is null or not @SCHEMA@.auth_enabled(s.account) then
|
|
766
|
-
perform @SCHEMA@.lt_fail('no_session'
|
|
766
|
+
perform @SCHEMA@.lt_fail('sql-access.no_session');
|
|
767
767
|
end if;
|
|
768
768
|
if p_tenant <> s.account and not (
|
|
769
769
|
exists (select 1 from @SCHEMA@.entity x
|
|
770
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)
|
|
771
771
|
and @SCHEMA@.auth_enabled(p_tenant)) then
|
|
772
|
-
perform @SCHEMA@.lt_fail('
|
|
772
|
+
perform @SCHEMA@.lt_fail('sql-access.no_membership');
|
|
773
773
|
end if;
|
|
774
774
|
update @SCHEMA@.secret x
|
|
775
775
|
set meta = case when p_tenant = s.account then x.meta - 'tenant' else x.meta || jsonb_build_object('tenant', p_tenant) end
|
|
@@ -850,10 +850,6 @@ begin
|
|
|
850
850
|
execute format('revoke all on function @SCHEMA@.%s from public', f);
|
|
851
851
|
end loop;
|
|
852
852
|
end $$;
|
|
853
|
-
-- до этапа 5 выпуск сессии сервисом принимал два аргумента; ранние сигнатуры OTP этапа 5
|
|
854
|
-
drop function if exists @SCHEMA@.issue_session(uuid, interval);
|
|
855
|
-
drop function if exists @SCHEMA@.auth_issue_otp(uuid, text, text, interval, int);
|
|
856
|
-
drop function if exists @SCHEMA@.login_otp(text, text, text, int);
|
|
857
853
|
grant execute on function
|
|
858
854
|
@SCHEMA@.issue_session(uuid, interval, text[]), @SCHEMA@.auth_password_get(text, text),
|
|
859
855
|
@SCHEMA@.auth_set_password(uuid, text, text, text, boolean, boolean), @SCHEMA@.auth_issue_apikey(uuid, text, interval),
|