@memberjunction/core 6.2.0-edge.5 → 6.2.0-edge.7
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/generic/BaseEntitySaveQueue.d.ts +15 -0
- package/dist/generic/BaseEntitySaveQueue.d.ts.map +1 -1
- package/dist/generic/BaseEntitySaveQueue.js +21 -0
- package/dist/generic/BaseEntitySaveQueue.js.map +1 -1
- package/dist/generic/EntityFieldRules.d.ts.map +1 -1
- package/dist/generic/EntityFieldRules.js +1 -0
- package/dist/generic/EntityFieldRules.js.map +1 -1
- package/dist/generic/alternateBaseViews.d.ts +119 -0
- package/dist/generic/alternateBaseViews.d.ts.map +1 -0
- package/dist/generic/alternateBaseViews.js +223 -0
- package/dist/generic/alternateBaseViews.js.map +1 -0
- package/dist/generic/baseEngine.d.ts +171 -17
- package/dist/generic/baseEngine.d.ts.map +1 -1
- package/dist/generic/baseEngine.js +722 -117
- package/dist/generic/baseEngine.js.map +1 -1
- package/dist/generic/baseEngineRegistry.d.ts.map +1 -1
- package/dist/generic/baseEngineRegistry.js +2 -1
- package/dist/generic/baseEngineRegistry.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +216 -21
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +969 -100
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/baseRemotableOperation.d.ts +95 -6
- package/dist/generic/baseRemotableOperation.d.ts.map +1 -1
- package/dist/generic/baseRemotableOperation.js +112 -8
- package/dist/generic/baseRemotableOperation.js.map +1 -1
- package/dist/generic/contextTokens.d.ts +136 -0
- package/dist/generic/contextTokens.d.ts.map +1 -0
- package/dist/generic/contextTokens.js +319 -0
- package/dist/generic/contextTokens.js.map +1 -0
- package/dist/generic/databaseProviderBase.d.ts +103 -5
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js +381 -52
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/embeddedRecord.d.ts +6 -0
- package/dist/generic/embeddedRecord.d.ts.map +1 -1
- package/dist/generic/embeddedRecord.js +15 -1
- package/dist/generic/embeddedRecord.js.map +1 -1
- package/dist/generic/entityCompanion.d.ts +7 -0
- package/dist/generic/entityCompanion.d.ts.map +1 -1
- package/dist/generic/entityCompanion.js +8 -0
- package/dist/generic/entityCompanion.js.map +1 -1
- package/dist/generic/entityInfo.d.ts +234 -9
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +592 -77
- package/dist/generic/entityInfo.js.map +1 -1
- package/dist/generic/entityValueFieldSecurity.d.ts +139 -0
- package/dist/generic/entityValueFieldSecurity.d.ts.map +1 -0
- package/dist/generic/entityValueFieldSecurity.js +250 -0
- package/dist/generic/entityValueFieldSecurity.js.map +1 -0
- package/dist/generic/externalDataSourceReadRouter.d.ts +10 -0
- package/dist/generic/externalDataSourceReadRouter.d.ts.map +1 -1
- package/dist/generic/externalDataSourceReadRouter.js +12 -0
- package/dist/generic/externalDataSourceReadRouter.js.map +1 -1
- package/dist/generic/fieldSecuritySQLGate.d.ts +359 -0
- package/dist/generic/fieldSecuritySQLGate.d.ts.map +1 -0
- package/dist/generic/fieldSecuritySQLGate.js +902 -0
- package/dist/generic/fieldSecuritySQLGate.js.map +1 -0
- package/dist/generic/indexRestrictedFields.d.ts +47 -0
- package/dist/generic/indexRestrictedFields.d.ts.map +1 -0
- package/dist/generic/indexRestrictedFields.js +129 -0
- package/dist/generic/indexRestrictedFields.js.map +1 -0
- package/dist/generic/interfaces.d.ts +64 -2
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/listMembershipFilter.d.ts +5 -0
- package/dist/generic/listMembershipFilter.d.ts.map +1 -0
- package/dist/generic/listMembershipFilter.js +23 -0
- package/dist/generic/listMembershipFilter.js.map +1 -0
- package/dist/generic/localCacheManager.d.ts +126 -14
- package/dist/generic/localCacheManager.d.ts.map +1 -1
- package/dist/generic/localCacheManager.js +348 -48
- package/dist/generic/localCacheManager.js.map +1 -1
- package/dist/generic/logging.d.ts.map +1 -1
- package/dist/generic/logging.js +7 -1
- package/dist/generic/logging.js.map +1 -1
- package/dist/generic/metadata.d.ts +3 -2
- package/dist/generic/metadata.d.ts.map +1 -1
- package/dist/generic/metadata.js +5 -2
- package/dist/generic/metadata.js.map +1 -1
- package/dist/generic/platformSQL.d.ts +54 -0
- package/dist/generic/platformSQL.d.ts.map +1 -1
- package/dist/generic/platformSQL.js +55 -0
- package/dist/generic/platformSQL.js.map +1 -1
- package/dist/generic/providerBase.d.ts +408 -57
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +1051 -310
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +13 -0
- package/dist/generic/queryInfo.d.ts.map +1 -1
- package/dist/generic/queryInfo.js +13 -0
- package/dist/generic/queryInfo.js.map +1 -1
- package/dist/generic/queryInfoInterfaces.d.ts +8 -0
- package/dist/generic/queryInfoInterfaces.d.ts.map +1 -1
- package/dist/generic/queryTemplateContext.d.ts +49 -0
- package/dist/generic/queryTemplateContext.d.ts.map +1 -0
- package/dist/generic/queryTemplateContext.js +113 -0
- package/dist/generic/queryTemplateContext.js.map +1 -0
- package/dist/generic/recordChangeFieldSecurity.d.ts.map +1 -1
- package/dist/generic/recordChangeFieldSecurity.js +13 -2
- package/dist/generic/recordChangeFieldSecurity.js.map +1 -1
- package/dist/generic/relatedRecordCollection.d.ts +18 -0
- package/dist/generic/relatedRecordCollection.d.ts.map +1 -1
- package/dist/generic/relatedRecordCollection.js +55 -7
- package/dist/generic/relatedRecordCollection.js.map +1 -1
- package/dist/generic/remoteOperationDispatch.d.ts.map +1 -1
- package/dist/generic/remoteOperationDispatch.js +14 -2
- package/dist/generic/remoteOperationDispatch.js.map +1 -1
- package/dist/generic/runQuery.d.ts +42 -0
- package/dist/generic/runQuery.d.ts.map +1 -1
- package/dist/generic/runQuery.js +14 -0
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.d.ts +33 -6
- package/dist/generic/runQuerySQLFilterImplementations.d.ts.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.js +119 -29
- package/dist/generic/runQuerySQLFilterImplementations.js.map +1 -1
- package/dist/generic/saveEntityGraphOperation.d.ts.map +1 -1
- package/dist/generic/saveEntityGraphOperation.js +3 -0
- package/dist/generic/saveEntityGraphOperation.js.map +1 -1
- package/dist/generic/securityInfo.d.ts +11 -0
- package/dist/generic/securityInfo.d.ts.map +1 -1
- package/dist/generic/securityInfo.js +15 -0
- package/dist/generic/securityInfo.js.map +1 -1
- package/dist/generic/telemetryManager.d.ts +9 -0
- package/dist/generic/telemetryManager.d.ts.map +1 -1
- package/dist/generic/telemetryManager.js +5 -1
- package/dist/generic/telemetryManager.js.map +1 -1
- package/dist/generic/transportError.d.ts +41 -0
- package/dist/generic/transportError.d.ts.map +1 -0
- package/dist/generic/transportError.js +167 -0
- package/dist/generic/transportError.js.map +1 -0
- package/dist/generic/util.d.ts +12 -0
- package/dist/generic/util.d.ts.map +1 -1
- package/dist/generic/util.js +52 -3
- package/dist/generic/util.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/views/runView.d.ts +102 -0
- package/dist/views/runView.d.ts.map +1 -1
- package/dist/views/runView.js +40 -0
- package/dist/views/runView.js.map +1 -1
- package/dist/views/viewProperties.d.ts +55 -0
- package/dist/views/viewProperties.d.ts.map +1 -0
- package/dist/views/viewProperties.js +258 -0
- package/dist/views/viewProperties.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { SQLScreeningDialect } from '@memberjunction/global';
|
|
2
|
+
import { EntityInfo, FieldSecurityError } from './entityInfo.js';
|
|
3
|
+
import { UserInfo } from './securityInfo.js';
|
|
4
|
+
/** Why {@link FieldSecuritySQLGate} refuses a piece of SQL. */
|
|
5
|
+
export type FieldSecurityViolationKind = 'DeniedField' | 'WholeRow' | 'Unresolvable' | 'UnknownRelation';
|
|
6
|
+
/** One reason {@link FieldSecuritySQLGate.FindViolation} refuses a piece of SQL. */
|
|
7
|
+
export interface FieldSecurityViolation {
|
|
8
|
+
Kind: FieldSecurityViolationKind;
|
|
9
|
+
/**
|
|
10
|
+
* `DeniedField`: the reference as the database reads it (a quoted identifier's bare name; on
|
|
11
|
+
* PostgreSQL an unquoted name in lower case). `WholeRow`: the construct, such as `FOR JSON`.
|
|
12
|
+
* `Unresolvable`: why the text could not be read. `UnknownRelation`: the relation the catalog
|
|
13
|
+
* does not know.
|
|
14
|
+
*/
|
|
15
|
+
Reference: string;
|
|
16
|
+
/** The entity whose denial the reference reaches; null when the text could not be read. */
|
|
17
|
+
Entity: EntityInfo | null;
|
|
18
|
+
}
|
|
19
|
+
/** What {@link FieldSecuritySQLGate} needs to judge one piece of SQL for one user. */
|
|
20
|
+
export interface FieldSecuritySQLContext {
|
|
21
|
+
/** The acting user. */
|
|
22
|
+
User: UserInfo;
|
|
23
|
+
/** The dialect whose lexical rules the database applies to the text. */
|
|
24
|
+
Dialect: SQLScreeningDialect;
|
|
25
|
+
/** Every entity the provider knows, so base views and tables named in the text are recognized. */
|
|
26
|
+
Catalog: readonly EntityInfo[];
|
|
27
|
+
/**
|
|
28
|
+
* For a filter, sort or aggregate fragment: the entity whose view the fragment runs against.
|
|
29
|
+
* Its columns can be named without a qualifier, so its denied fields are always checked.
|
|
30
|
+
*/
|
|
31
|
+
TargetEntity?: EntityInfo | null;
|
|
32
|
+
/** Entities the SQL is known to read beyond those its text names, such as a query's declared entities. */
|
|
33
|
+
ReadEntities?: readonly EntityInfo[];
|
|
34
|
+
/**
|
|
35
|
+
* For a whole statement, such as a saved query's SQL: refuse, for a user carrying any field
|
|
36
|
+
* denial, a relation that is not a CTE and not the base view or base table of a catalog entity
|
|
37
|
+
* (a custom view, synonym, table-valued function, temp table, or a name in another schema or
|
|
38
|
+
* database), and `EXEC`/`CALL`. What such a relation reads cannot be checked.
|
|
39
|
+
*/
|
|
40
|
+
RefuseUnknownRelations?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* For a saved query's rendered SQL: the character offsets of `*` tokens that a structural
|
|
43
|
+
* reading of the whole statement has shown reach the caller only as output columns (a plain
|
|
44
|
+
* `*` or `alias.*` select item of a block whose rows become the result unchanged in shape).
|
|
45
|
+
* Such a star is not refused as a whole-row read; the caller must instead drop the denied
|
|
46
|
+
* columns it brings from the result. Every other star is judged as usual.
|
|
47
|
+
*/
|
|
48
|
+
ProjectionStarOffsets?: ReadonlySet<number>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* SECURITY — the field-level security gate for SQL text a caller authors: RunView filters, sorts and
|
|
52
|
+
* aggregate expressions, a saved view's stored clauses, dataset item filters, and the rendered SQL
|
|
53
|
+
* of a saved query.
|
|
54
|
+
*
|
|
55
|
+
* Output projection alone is not enough. A user denied `Salary` who can write
|
|
56
|
+
* `ExtraFilter: "Salary > 200000"`, sort by it, or aggregate `MIN(Salary)` reconstructs its values
|
|
57
|
+
* from which rows come back. This gate refuses such text before it reaches the cache or the
|
|
58
|
+
* database, for every caller: client requests, agents and actions alike.
|
|
59
|
+
*
|
|
60
|
+
* ## How it reads the text
|
|
61
|
+
*
|
|
62
|
+
* The text is split into tokens with the database's own lexical rules
|
|
63
|
+
* (`ScanSQLForScreening`), so a name inside a string literal or a comment is not a reference, and a
|
|
64
|
+
* `[bracketed]` or `"quoted"` name is read as the bare name it is. Every unquoted word and quoted
|
|
65
|
+
* identifier is then compared with every denied field of every entity the SQL reads:
|
|
66
|
+
* - the entity the fragment filters (its columns can be named unqualified);
|
|
67
|
+
* - the entities whose base view or base table the text names, such as a subquery's FROM;
|
|
68
|
+
* - any entities the caller says the SQL reads.
|
|
69
|
+
*
|
|
70
|
+
* A name matches a denied field by the rule `IdentifierMatches` states, or when the two are equal
|
|
71
|
+
* after Unicode compatibility folding, accent stripping and case folding, the comparisons a
|
|
72
|
+
* database collation can make. So a look-alike spelling that the database would still resolve to
|
|
73
|
+
* the denied column is refused too. Each name is compared on its own, so one denied name inside
|
|
74
|
+
* another can never hide it.
|
|
75
|
+
*
|
|
76
|
+
* A reference qualified by an alias or view name that binds only to entities whose denied set
|
|
77
|
+
* does not hold that name is not a reference to a denied field. An unknown qualifier is checked
|
|
78
|
+
* against every restricted entity.
|
|
79
|
+
*
|
|
80
|
+
* ## Whole-row constructs
|
|
81
|
+
*
|
|
82
|
+
* For a user denied something on an entity the SQL reads, constructs that read a whole row without
|
|
83
|
+
* naming its columns are refused: `SELECT *` and `alias.*` (except directly inside `EXISTS (…)`
|
|
84
|
+
* whose body has no set operation or row-picking ORDER BY), `FOR JSON`, `FOR XML`, any function of
|
|
85
|
+
* `*` other than `COUNT(*)`/`COUNT_BIG(*)` (for example `CHECKSUM(*)`), `NATURAL JOIN`, a column
|
|
86
|
+
* alias list on such a relation, and a relation or its alias used as a value (PostgreSQL's
|
|
87
|
+
* whole-row reference, as in `row_to_json(e)` or `TABLE vw`). A user with no denials on the
|
|
88
|
+
* entities read is not affected; ordinary subqueries keep working.
|
|
89
|
+
*
|
|
90
|
+
* ## Failing closed
|
|
91
|
+
*
|
|
92
|
+
* Text the scanner cannot read the way the database does is refused for any user who carries a
|
|
93
|
+
* denial on an entity the SQL could read. So is a name holding a control, format or
|
|
94
|
+
* default-ignorable character (a zero-width joiner, a direction mark), which a collation may give
|
|
95
|
+
* no weight to.
|
|
96
|
+
*
|
|
97
|
+
* ## Unknown columns
|
|
98
|
+
*
|
|
99
|
+
* A reference to a column that does not exist reaches the database, which rejects it. For a user
|
|
100
|
+
* carrying denials, {@link FieldSecuritySQLGate.ErrorForInvalidColumn} turns that rejection into the
|
|
101
|
+
* same {@link FieldSecurityError} a denied column gets, so the two cannot be told apart.
|
|
102
|
+
*/
|
|
103
|
+
export declare class FieldSecuritySQLGate {
|
|
104
|
+
/**
|
|
105
|
+
* The first reason `sql` must be refused for `context.User`, or null when it may run.
|
|
106
|
+
*
|
|
107
|
+
* @param sql A filter, sort or aggregate fragment, or a whole statement
|
|
108
|
+
* @param context The user, dialect, catalog and the entities the SQL is known to read
|
|
109
|
+
*/
|
|
110
|
+
static FindViolation(sql: string | null | undefined, context: FieldSecuritySQLContext): FieldSecurityViolation | null;
|
|
111
|
+
/**
|
|
112
|
+
* The first reason the sort fragment `orderBy` must be refused for `context.User`, or null.
|
|
113
|
+
* Everything {@link FindViolation} refuses, and, for a user denied a field on
|
|
114
|
+
* `context.TargetEntity`, a sort item that is a column position (`3 DESC`). A position names a
|
|
115
|
+
* column of the select list without spelling it, and an entity-object read selects every
|
|
116
|
+
* column, so `ORDER BY 3` can sort by a denied field. It is refused as a whole-row construct.
|
|
117
|
+
*/
|
|
118
|
+
static FindSortViolation(orderBy: string | null | undefined, context: FieldSecuritySQLContext): FieldSecurityViolation | null;
|
|
119
|
+
/**
|
|
120
|
+
* Throws a {@link FieldSecurityError} when {@link FindViolation} refuses `sql`. The error names
|
|
121
|
+
* `entityName`, the entity the caller is reading, never the entity a subquery reaches, so a
|
|
122
|
+
* refusal says nothing a "no such column" error would not.
|
|
123
|
+
*/
|
|
124
|
+
static AssertAllowed(sql: string | null | undefined, context: FieldSecuritySQLContext, entityName: string): void;
|
|
125
|
+
/**
|
|
126
|
+
* Checks a whole statement, such as a saved query's rendered SQL, against the denied fields of
|
|
127
|
+
* every entity it reads. The entities come from the base views and tables the text names, plus
|
|
128
|
+
* `readEntities`. References are checked wherever they appear: the select list, WHERE, JOIN,
|
|
129
|
+
* GROUP BY, ORDER BY and HAVING. For a user carrying any field denial, a relation the catalog
|
|
130
|
+
* does not know is refused too ({@link FieldSecuritySQLContext.RefuseUnknownRelations}).
|
|
131
|
+
* Throws a {@link FieldSecurityError} on the first violation, naming the entity whose denial
|
|
132
|
+
* it reached (or `fallbackEntityName` when none).
|
|
133
|
+
*/
|
|
134
|
+
static AssertStatementAllowed(sql: string, user: UserInfo, catalog: readonly EntityInfo[], dialect: SQLScreeningDialect, readEntities?: readonly EntityInfo[], fallbackEntityName?: string): void;
|
|
135
|
+
/** The error a violation raises, naming `entityName`. */
|
|
136
|
+
static ErrorForViolation(violation: FieldSecurityViolation, entityName: string): FieldSecurityError;
|
|
137
|
+
/**
|
|
138
|
+
* For a user carrying field denials on `entity`, the {@link FieldSecurityError} a database's
|
|
139
|
+
* "no such column" rejection becomes, so a column that does not exist and a column that is
|
|
140
|
+
* denied produce the same error. Null when the user carries no denials there, or the error is
|
|
141
|
+
* not a "no such column" rejection.
|
|
142
|
+
*
|
|
143
|
+
* Reads SQL Server's `Invalid column name 'x'` and `The multi-part identifier "a.x" could not be
|
|
144
|
+
* bound`, and PostgreSQL's `column "x" does not exist` and `column a.x does not exist`.
|
|
145
|
+
*/
|
|
146
|
+
static ErrorForInvalidColumn(error: unknown, entity: EntityInfo | null | undefined, user: UserInfo | null | undefined): FieldSecurityError | null;
|
|
147
|
+
/**
|
|
148
|
+
* The entities whose base view or base table `sql` reads as a relation: a name after FROM, JOIN
|
|
149
|
+
* or APPLY, or in a FROM list, wherever it appears (subqueries and CTE bodies included), with
|
|
150
|
+
* schema qualifiers skipped. A name in a literal or a comment is not a relation. A bare name
|
|
151
|
+
* shared by entities in several schemas yields each of them, so the set never misses a read.
|
|
152
|
+
* A relation inside a parenthesized join and PostgreSQL's `FROM ONLY x` count too. Null when
|
|
153
|
+
* the text cannot be read the way the database reads it.
|
|
154
|
+
*/
|
|
155
|
+
static RelationEntities(sql: string | null | undefined, catalog: readonly EntityInfo[], dialect: SQLScreeningDialect): EntityInfo[] | null;
|
|
156
|
+
/** True when `user` is denied at least one field on at least one of `entities`. */
|
|
157
|
+
static UserCarriesDenials(entities: Iterable<EntityInfo | null | undefined>, user: UserInfo): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* True when `user` is denied at least one field on any entity of `catalog`.
|
|
160
|
+
*
|
|
161
|
+
* Memoized per (catalog, user): after the first call it costs a few comparisons. The memo is
|
|
162
|
+
* discarded when the catalog array changes length, when the field-security generation moves
|
|
163
|
+
* (an entity rebuilt, a flag assigned, a cache invalidated; see
|
|
164
|
+
* `CurrentFieldSecurityGeneration`) or when the user's roles change, which are everything the
|
|
165
|
+
* answer depends on. A catalog swapped for a new array starts a new memo.
|
|
166
|
+
*/
|
|
167
|
+
static CatalogHasDenialsForUser(catalog: readonly EntityInfo[] | null | undefined, user: UserInfo): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Every field `user` may not read across `catalog`: one `entityID:field,field` entry per
|
|
170
|
+
* entity on which the user is denied something, sorted. '' for a user denied nothing.
|
|
171
|
+
* Memoized exactly as {@link CatalogHasDenialsForUser}.
|
|
172
|
+
*/
|
|
173
|
+
static CatalogDenialProfileKey(catalog: readonly EntityInfo[] | null | undefined, user: UserInfo): string;
|
|
174
|
+
/** The current summary for (`catalog`, `user`), rebuilt when any part of its key moved. */
|
|
175
|
+
private static catalogDenialSummary;
|
|
176
|
+
/** The uncached walk behind {@link CatalogDenialProfileKey}. */
|
|
177
|
+
private static buildDenialProfileKey;
|
|
178
|
+
/**
|
|
179
|
+
* The column a database "no such column" message names, or null. A qualified name gives its
|
|
180
|
+
* last part, which is what the gate reports for the same reference.
|
|
181
|
+
*/
|
|
182
|
+
private static invalidColumnName;
|
|
183
|
+
/** Longest prefix of a database error message scanned for a column name. */
|
|
184
|
+
private static readonly maxErrorMessageScanLength;
|
|
185
|
+
/** The last dot-separated part of an identifier path, unquoted and unescaped. */
|
|
186
|
+
private static lastIdentifierPart;
|
|
187
|
+
/**
|
|
188
|
+
* The identifier path in a PostgreSQL `column <path> does not exist` message (for example
|
|
189
|
+
* `e.salry` or `"E"."Salry"`), or null. Scanned by hand rather than with a regular expression:
|
|
190
|
+
* the path's parts may themselves contain dots, and a pattern that allows that backtracks
|
|
191
|
+
* exponentially on crafted input.
|
|
192
|
+
*/
|
|
193
|
+
private static postgresColumnPath;
|
|
194
|
+
/**
|
|
195
|
+
* Index just past an identifier path starting at `start`: a run of non-space characters in
|
|
196
|
+
* which double-quoted segments (with `""` escapes) may contain spaces. Returns `start` when no
|
|
197
|
+
* path starts there, and -1 for an unterminated quote.
|
|
198
|
+
*/
|
|
199
|
+
private static identifierPathEnd;
|
|
200
|
+
/**
|
|
201
|
+
* The first call of a function the dialect forbids in caller SQL (one that runs SQL given as a
|
|
202
|
+
* string, reads files or other databases), or null. What such a call reads cannot be checked.
|
|
203
|
+
*/
|
|
204
|
+
private static findDynamicSQLCall;
|
|
205
|
+
/**
|
|
206
|
+
* True when the user carries a denial on any entity the SQL could read: the target, the
|
|
207
|
+
* declared read entities (checked directly, as they need not be catalog members), or any
|
|
208
|
+
* catalog entity, since the text can name any of them. The catalog answer is memoized
|
|
209
|
+
* ({@link CatalogHasDenialsForUser}).
|
|
210
|
+
*
|
|
211
|
+
* Deliberately catalog-wide rather than "the target and read entities only". Which other
|
|
212
|
+
* entities a fragment reads is only known once its text has been read the way the database
|
|
213
|
+
* reads it: a subquery, a parenthesized join, a schema-qualified or bracketed name, or a name
|
|
214
|
+
* spelled with look-alike characters all reach another entity's view. And text that cannot be
|
|
215
|
+
* read at all, a dynamic-SQL call or an invisible character must be refused for such a user
|
|
216
|
+
* whatever it appears to name. Every one of those checks needs the tokens, so a user with a
|
|
217
|
+
* denial anywhere has every fragment tokenized; {@link analyze} then derives the read set, and
|
|
218
|
+
* a fragment whose read set carries none of the user's denials passes without the
|
|
219
|
+
* denied-name and whole-row checks.
|
|
220
|
+
*/
|
|
221
|
+
private static mayReadRestrictedEntity;
|
|
222
|
+
/** Builds the relation bindings, the restricted set and its denied names. */
|
|
223
|
+
private static analyze;
|
|
224
|
+
/** Adds `entity` to the restricted set when the user is denied a field on it. */
|
|
225
|
+
private static addIfRestricted;
|
|
226
|
+
/** Records each relation the text names, its alias, and which of them are restricted. */
|
|
227
|
+
private static bindRelations;
|
|
228
|
+
/** Binds a qualifier to entities. */
|
|
229
|
+
private static bind;
|
|
230
|
+
/**
|
|
231
|
+
* Whether the relation name at `i` declares a relation: it follows FROM, JOIN or APPLY, or a
|
|
232
|
+
* comma in a FROM list, with any `schema .` / `database . schema .` qualifiers, a PostgreSQL
|
|
233
|
+
* `ONLY`, and the parentheses of a parenthesized join skipped.
|
|
234
|
+
*/
|
|
235
|
+
private static isRelationDeclaration;
|
|
236
|
+
/** Whether the token at `j` is a FROM, JOIN or APPLY keyword, or a comma in a FROM list. */
|
|
237
|
+
private static introducesRelation;
|
|
238
|
+
/** The index of the first part of the dotted name that ends at `i` (`db . schema . name`). */
|
|
239
|
+
private static qualifierStart;
|
|
240
|
+
/**
|
|
241
|
+
* The clause keyword that governs the token at `i` at its own parenthesis depth: the nearest
|
|
242
|
+
* preceding SELECT, FROM, JOIN, WHERE, ON, GROUP, ORDER or HAVING at that depth. Inside the
|
|
243
|
+
* parentheses of a parenthesized join (`FROM (a x, b y)`) with no such keyword, `from`.
|
|
244
|
+
*/
|
|
245
|
+
private static clauseAt;
|
|
246
|
+
/** Whether the `(` at `j` opens a parenthesized join: it stands where a relation is declared. */
|
|
247
|
+
private static opensJoinGroup;
|
|
248
|
+
/**
|
|
249
|
+
* The first relation the statement reads that is not a CTE and not the base view or base table
|
|
250
|
+
* of a catalog entity, or a stored-procedure call; null when there is none. A name qualified by
|
|
251
|
+
* a schema no entity of that name lives in, or by a database, is unknown; so is a function in
|
|
252
|
+
* a relation position (`FROM f(…)`).
|
|
253
|
+
*/
|
|
254
|
+
private static findUnknownRelation;
|
|
255
|
+
/**
|
|
256
|
+
* Whether the name at `i` is the last part of a relation the statement reads: after FROM (of a
|
|
257
|
+
* SELECT, not `EXTRACT(… FROM x)` or `IS DISTINCT FROM x`), JOIN, APPLY, a FROM-list comma or
|
|
258
|
+
* PostgreSQL's `TABLE`, past qualifiers, `ONLY`, `LATERAL` and join-group parentheses.
|
|
259
|
+
*/
|
|
260
|
+
private static isRelationTarget;
|
|
261
|
+
/** Whether a token is `ONLY` or `LATERAL`. */
|
|
262
|
+
private static isRelationModifier;
|
|
263
|
+
/** Whether the FROM at `j` is a SELECT's FROM clause. */
|
|
264
|
+
private static isSelectFrom;
|
|
265
|
+
/**
|
|
266
|
+
* Whether the relation whose last name part is at `i` is a CTE or a catalog entity's base view
|
|
267
|
+
* or base table, in that entity's schema when qualified.
|
|
268
|
+
*/
|
|
269
|
+
private static isKnownRelation;
|
|
270
|
+
/**
|
|
271
|
+
* The folded names of the CTEs a statement defines: a name after WITH, RECURSIVE or a comma
|
|
272
|
+
* that is followed by an optional column list, AS, an optional `[NOT] MATERIALIZED`, and `(`.
|
|
273
|
+
*/
|
|
274
|
+
private static cteNames;
|
|
275
|
+
/** Whether the tokens from `j` are `[(columns)] AS [NOT] [MATERIALIZED] (`. */
|
|
276
|
+
private static opensCTEBody;
|
|
277
|
+
/** The index of the `)` that closes the `(` at `open`, or -1. */
|
|
278
|
+
private static closingParen;
|
|
279
|
+
/**
|
|
280
|
+
* Whether the body of the `EXISTS (` whose parenthesis is at `open` has, at its own depth, a
|
|
281
|
+
* word that makes a `SELECT *` there read column values ({@link EXISTS_ROW_READING_WORDS}).
|
|
282
|
+
* An unclosed body counts as one that does.
|
|
283
|
+
*/
|
|
284
|
+
private static existsBodyReadsRows;
|
|
285
|
+
/** The index of the alias after the relation at `i` (`x a`, `x AS a`), or null. */
|
|
286
|
+
private static aliasIndexAfter;
|
|
287
|
+
/** The first reference to a denied field, honoring qualifiers that bind to known entities. */
|
|
288
|
+
private static findDeniedReference;
|
|
289
|
+
/**
|
|
290
|
+
* The denied names a reference at `i` could reach: those of the entities its qualifier binds to,
|
|
291
|
+
* or every restricted entity's when it is unqualified or its qualifier is unknown.
|
|
292
|
+
*/
|
|
293
|
+
private static candidatesFor;
|
|
294
|
+
/**
|
|
295
|
+
* A sort item of `orderBy` that is a column position, as a whole-row violation, or null. Only
|
|
296
|
+
* for a user denied a field on the target entity. An item counts when its first token, inside
|
|
297
|
+
* any opening parentheses, is a number.
|
|
298
|
+
*/
|
|
299
|
+
private static findSortByPosition;
|
|
300
|
+
/** The first whole-row construct, or null. */
|
|
301
|
+
private static findWholeRowConstruct;
|
|
302
|
+
/** The whole-row construct that starts at token `i`, or null. */
|
|
303
|
+
private static wholeRowConstructAt;
|
|
304
|
+
/**
|
|
305
|
+
* What a `*` at `i` reads: null for a multiplication, `COUNT(*)`, `EXISTS (SELECT *` whose body
|
|
306
|
+
* has no set operation or row-picking ORDER BY at its own depth, `alias.*` whose alias binds
|
|
307
|
+
* only to entities the user is denied nothing on, or a projection star
|
|
308
|
+
* ({@link FieldSecuritySQLContext.ProjectionStarOffsets}).
|
|
309
|
+
*/
|
|
310
|
+
private static starConstruct;
|
|
311
|
+
/**
|
|
312
|
+
* A restricted relation name or alias used other than as a declaration or a qualifier (`x.`):
|
|
313
|
+
* a whole-row value on PostgreSQL, or a column alias list after the declaration.
|
|
314
|
+
*/
|
|
315
|
+
private static relationValueConstruct;
|
|
316
|
+
/** Whether a token can end the left operand of a multiplication. */
|
|
317
|
+
private static endsOperand;
|
|
318
|
+
/** Whether a token can start the right operand of a multiplication. */
|
|
319
|
+
private static startsOperand;
|
|
320
|
+
/**
|
|
321
|
+
* The name a "no such column" error would give for `name` as `sql` writes it, so a denied
|
|
322
|
+
* column is reported exactly as an unknown one. On PostgreSQL, MJ quotes a capitalized or
|
|
323
|
+
* dot-qualified word before the database sees it (`AutoQuoteLeavesWordBare`), so the error
|
|
324
|
+
* names such a word as written; a word left bare is folded to lower case. A quoted name, and
|
|
325
|
+
* every name on SQL Server, is reported as written. The first token spelled `name` decides.
|
|
326
|
+
*
|
|
327
|
+
* @param sql The caller's SQL
|
|
328
|
+
* @param name The reference as the database reads it
|
|
329
|
+
* @param dialect The dialect the SQL runs under
|
|
330
|
+
*/
|
|
331
|
+
static ReportedColumnName(sql: string, name: string, dialect: SQLScreeningDialect): string;
|
|
332
|
+
/** A reference's name as {@link ReportedColumnName} gives it. */
|
|
333
|
+
private static reportedName;
|
|
334
|
+
private static isName;
|
|
335
|
+
private static isWord;
|
|
336
|
+
private static isSymbol;
|
|
337
|
+
/** Folded base view and base table names of every entity in the catalog. */
|
|
338
|
+
private static relationIndex;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* An identifier reduced to the form a database collation may compare it in: Unicode compatibility
|
|
342
|
+
* decomposition (a KELVIN SIGN reads as `K`, a full-width letter as its ASCII form), accents and
|
|
343
|
+
* other combining marks removed, control, format and default-ignorable characters (zero-width
|
|
344
|
+
* joiners, direction marks, a soft hyphen) removed, case folded through upper case (`ß` and `ẞ` both read `ss`, a
|
|
345
|
+
* final `ς` reads `σ`), and surrounding spaces trimmed.
|
|
346
|
+
*/
|
|
347
|
+
export declare function FoldIdentifier(name: string): string;
|
|
348
|
+
/**
|
|
349
|
+
* Whether a reference as written may name `fieldName` on some database: by the rule
|
|
350
|
+
* `IdentifierMatches` states, or when both fold to the same form ({@link FoldIdentifier}). Looser
|
|
351
|
+
* than any collation, so a security check that refuses on it never lets through a reference the
|
|
352
|
+
* database would resolve to the field.
|
|
353
|
+
*/
|
|
354
|
+
export declare function ReferenceMayNameField(reference: string, fieldName: string): boolean;
|
|
355
|
+
/** The message for a whole-row construct refused for a user carrying field denials. */
|
|
356
|
+
export declare function FieldSecurityWholeRowMessage(construct: string, entityName: string): string;
|
|
357
|
+
/** The message for SQL that could not be read well enough to check against field permissions. */
|
|
358
|
+
export declare function FieldSecurityUnresolvableSQLMessage(entityName: string): string;
|
|
359
|
+
//# sourceMappingURL=fieldSecuritySQLGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldSecuritySQLGate.d.ts","sourceRoot":"","sources":["../../src/generic/fieldSecuritySQLGate.ts"],"names":[],"mappings":"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"}
|