@matter/protocol 0.12.4-alpha.0-20250210-ad8edf096 → 0.12.4-alpha.0-20250212-b2729c9eb
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/cjs/action/Interactable.d.ts +36 -0
- package/dist/cjs/action/Interactable.d.ts.map +1 -0
- package/dist/cjs/action/Interactable.js +22 -0
- package/dist/cjs/action/Interactable.js.map +6 -0
- package/dist/cjs/action/Val.d.ts +94 -0
- package/dist/cjs/action/Val.d.ts.map +1 -0
- package/dist/cjs/action/Val.js +33 -0
- package/dist/cjs/action/Val.js.map +6 -0
- package/dist/cjs/action/errors.d.ts +69 -0
- package/dist/cjs/action/errors.d.ts.map +1 -0
- package/dist/cjs/action/errors.js +108 -0
- package/dist/cjs/action/errors.js.map +6 -0
- package/dist/cjs/action/index.d.ts +13 -0
- package/dist/cjs/action/index.d.ts.map +1 -0
- package/dist/cjs/action/index.js +30 -0
- package/dist/cjs/action/index.js.map +6 -0
- package/dist/cjs/action/protocols.d.ts +118 -0
- package/dist/cjs/action/protocols.d.ts.map +1 -0
- package/dist/cjs/action/protocols.js +22 -0
- package/dist/cjs/action/protocols.js.map +6 -0
- package/dist/cjs/action/request/Invoke.d.ts +35 -0
- package/dist/cjs/action/request/Invoke.d.ts.map +1 -0
- package/dist/cjs/action/request/Invoke.js +80 -0
- package/dist/cjs/action/request/Invoke.js.map +6 -0
- package/dist/cjs/action/request/MalformedRequestError.d.ts +14 -0
- package/dist/cjs/action/request/MalformedRequestError.d.ts.map +1 -0
- package/dist/cjs/action/request/MalformedRequestError.js +32 -0
- package/dist/cjs/action/request/MalformedRequestError.js.map +6 -0
- package/dist/cjs/action/request/Read.d.ts +141 -0
- package/dist/cjs/action/request/Read.d.ts.map +1 -0
- package/dist/cjs/action/request/Read.js +173 -0
- package/dist/cjs/action/request/Read.js.map +6 -0
- package/dist/cjs/action/request/Specifier.d.ts +82 -0
- package/dist/cjs/action/request/Specifier.d.ts.map +1 -0
- package/dist/cjs/action/request/Specifier.js +88 -0
- package/dist/cjs/action/request/Specifier.js.map +6 -0
- package/dist/cjs/action/request/Subscribe.d.ts +26 -0
- package/dist/cjs/action/request/Subscribe.d.ts.map +1 -0
- package/dist/cjs/action/request/Subscribe.js +50 -0
- package/dist/cjs/action/request/Subscribe.js.map +6 -0
- package/dist/cjs/action/request/Write.d.ts +10 -0
- package/dist/cjs/action/request/Write.d.ts.map +1 -0
- package/dist/cjs/action/request/Write.js +22 -0
- package/dist/cjs/action/request/Write.js.map +6 -0
- package/dist/cjs/action/request/index.d.ts +11 -0
- package/dist/cjs/action/request/index.d.ts.map +1 -0
- package/dist/cjs/action/request/index.js +28 -0
- package/dist/cjs/action/request/index.js.map +6 -0
- package/dist/cjs/action/response/InvokeResult.d.ts +15 -0
- package/dist/cjs/action/response/InvokeResult.d.ts.map +1 -0
- package/dist/cjs/action/response/InvokeResult.js +22 -0
- package/dist/cjs/action/response/InvokeResult.js.map +6 -0
- package/dist/cjs/action/response/ReadResult.d.ts +63 -0
- package/dist/cjs/action/response/ReadResult.d.ts.map +1 -0
- package/dist/cjs/action/response/ReadResult.js +22 -0
- package/dist/cjs/action/response/ReadResult.js.map +6 -0
- package/dist/cjs/action/response/SubscribeResult.d.ts +13 -0
- package/dist/cjs/action/response/SubscribeResult.d.ts.map +1 -0
- package/dist/cjs/action/response/SubscribeResult.js +22 -0
- package/dist/cjs/action/response/SubscribeResult.js.map +6 -0
- package/dist/cjs/action/response/WriteResult.d.ts +12 -0
- package/dist/cjs/action/response/WriteResult.d.ts.map +1 -0
- package/dist/cjs/action/response/WriteResult.js +22 -0
- package/dist/cjs/action/response/WriteResult.js.map +6 -0
- package/dist/cjs/action/response/index.d.ts +10 -0
- package/dist/cjs/action/response/index.d.ts.map +1 -0
- package/dist/cjs/action/response/index.js +27 -0
- package/dist/cjs/action/response/index.js.map +6 -0
- package/dist/cjs/action/server/AccessControl.d.ts +152 -0
- package/dist/cjs/action/server/AccessControl.d.ts.map +1 -0
- package/dist/cjs/action/server/AccessControl.js +287 -0
- package/dist/cjs/action/server/AccessControl.js.map +6 -0
- package/dist/cjs/action/server/AttributeResponse.d.ts +36 -0
- package/dist/cjs/action/server/AttributeResponse.d.ts.map +1 -0
- package/dist/cjs/action/server/AttributeResponse.js +352 -0
- package/dist/cjs/action/server/AttributeResponse.js.map +6 -0
- package/dist/cjs/action/server/ServerInteraction.d.ts +35 -0
- package/dist/cjs/action/server/ServerInteraction.d.ts.map +1 -0
- package/dist/cjs/action/server/ServerInteraction.js +52 -0
- package/dist/cjs/action/server/ServerInteraction.js.map +6 -0
- package/dist/cjs/action/server/index.d.ts +9 -0
- package/dist/cjs/action/server/index.d.ts.map +1 -0
- package/dist/cjs/action/server/index.js +26 -0
- package/dist/cjs/action/server/index.js.map +6 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interaction/AccessControlManager.d.ts +1 -1
- package/dist/cjs/interaction/AccessControlManager.d.ts.map +1 -1
- package/dist/cjs/interaction/AccessControlManager.js +2 -2
- package/dist/cjs/interaction/AccessControlManager.js.map +1 -1
- package/dist/cjs/interaction/AttributeDataEncoder.d.ts +1 -3
- package/dist/cjs/interaction/AttributeDataEncoder.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts +5 -5
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionServer.d.ts +1 -1
- package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionServer.js +2 -2
- package/dist/cjs/interaction/InteractionServer.js.map +1 -1
- package/dist/cjs/interaction/ServerSubscription.d.ts +2 -2
- package/dist/cjs/interaction/ServerSubscription.d.ts.map +1 -1
- package/dist/cjs/interaction/ServerSubscription.js +0 -1
- package/dist/cjs/interaction/ServerSubscription.js.map +1 -1
- package/dist/cjs/mdns/MdnsScanner.d.ts +2 -2
- package/dist/esm/action/Interactable.d.ts +36 -0
- package/dist/esm/action/Interactable.d.ts.map +1 -0
- package/dist/esm/action/Interactable.js +6 -0
- package/dist/esm/action/Interactable.js.map +6 -0
- package/dist/esm/action/Val.d.ts +94 -0
- package/dist/esm/action/Val.d.ts.map +1 -0
- package/dist/esm/action/Val.js +13 -0
- package/dist/esm/action/Val.js.map +6 -0
- package/dist/esm/action/errors.d.ts +69 -0
- package/dist/esm/action/errors.d.ts.map +1 -0
- package/dist/esm/action/errors.js +88 -0
- package/dist/esm/action/errors.js.map +6 -0
- package/dist/esm/action/index.d.ts +13 -0
- package/dist/esm/action/index.d.ts.map +1 -0
- package/dist/esm/action/index.js +13 -0
- package/dist/esm/action/index.js.map +6 -0
- package/dist/esm/action/protocols.d.ts +118 -0
- package/dist/esm/action/protocols.d.ts.map +1 -0
- package/dist/esm/action/protocols.js +6 -0
- package/dist/esm/action/protocols.js.map +6 -0
- package/dist/esm/action/request/Invoke.d.ts +35 -0
- package/dist/esm/action/request/Invoke.d.ts.map +1 -0
- package/dist/esm/action/request/Invoke.js +60 -0
- package/dist/esm/action/request/Invoke.js.map +6 -0
- package/dist/esm/action/request/MalformedRequestError.d.ts +14 -0
- package/dist/esm/action/request/MalformedRequestError.d.ts.map +1 -0
- package/dist/esm/action/request/MalformedRequestError.js +12 -0
- package/dist/esm/action/request/MalformedRequestError.js.map +6 -0
- package/dist/esm/action/request/Read.d.ts +141 -0
- package/dist/esm/action/request/Read.d.ts.map +1 -0
- package/dist/esm/action/request/Read.js +153 -0
- package/dist/esm/action/request/Read.js.map +6 -0
- package/dist/esm/action/request/Specifier.d.ts +82 -0
- package/dist/esm/action/request/Specifier.d.ts.map +1 -0
- package/dist/esm/action/request/Specifier.js +68 -0
- package/dist/esm/action/request/Specifier.js.map +6 -0
- package/dist/esm/action/request/Subscribe.d.ts +26 -0
- package/dist/esm/action/request/Subscribe.d.ts.map +1 -0
- package/dist/esm/action/request/Subscribe.js +30 -0
- package/dist/esm/action/request/Subscribe.js.map +6 -0
- package/dist/esm/action/request/Write.d.ts +10 -0
- package/dist/esm/action/request/Write.d.ts.map +1 -0
- package/dist/esm/action/request/Write.js +6 -0
- package/dist/esm/action/request/Write.js.map +6 -0
- package/dist/esm/action/request/index.d.ts +11 -0
- package/dist/esm/action/request/index.d.ts.map +1 -0
- package/dist/esm/action/request/index.js +11 -0
- package/dist/esm/action/request/index.js.map +6 -0
- package/dist/esm/action/response/InvokeResult.d.ts +15 -0
- package/dist/esm/action/response/InvokeResult.d.ts.map +1 -0
- package/dist/esm/action/response/InvokeResult.js +6 -0
- package/dist/esm/action/response/InvokeResult.js.map +6 -0
- package/dist/esm/action/response/ReadResult.d.ts +63 -0
- package/dist/esm/action/response/ReadResult.d.ts.map +1 -0
- package/dist/esm/action/response/ReadResult.js +6 -0
- package/dist/esm/action/response/ReadResult.js.map +6 -0
- package/dist/esm/action/response/SubscribeResult.d.ts +13 -0
- package/dist/esm/action/response/SubscribeResult.d.ts.map +1 -0
- package/dist/esm/action/response/SubscribeResult.js +6 -0
- package/dist/esm/action/response/SubscribeResult.js.map +6 -0
- package/dist/esm/action/response/WriteResult.d.ts +12 -0
- package/dist/esm/action/response/WriteResult.d.ts.map +1 -0
- package/dist/esm/action/response/WriteResult.js +6 -0
- package/dist/esm/action/response/WriteResult.js.map +6 -0
- package/dist/esm/action/response/index.d.ts +10 -0
- package/dist/esm/action/response/index.d.ts.map +1 -0
- package/dist/esm/action/response/index.js +10 -0
- package/dist/esm/action/response/index.js.map +6 -0
- package/dist/esm/action/server/AccessControl.d.ts +152 -0
- package/dist/esm/action/server/AccessControl.d.ts.map +1 -0
- package/dist/esm/action/server/AccessControl.js +267 -0
- package/dist/esm/action/server/AccessControl.js.map +6 -0
- package/dist/esm/action/server/AttributeResponse.d.ts +36 -0
- package/dist/esm/action/server/AttributeResponse.d.ts.map +1 -0
- package/dist/esm/action/server/AttributeResponse.js +339 -0
- package/dist/esm/action/server/AttributeResponse.js.map +6 -0
- package/dist/esm/action/server/ServerInteraction.d.ts +35 -0
- package/dist/esm/action/server/ServerInteraction.d.ts.map +1 -0
- package/dist/esm/action/server/ServerInteraction.js +32 -0
- package/dist/esm/action/server/ServerInteraction.js.map +6 -0
- package/dist/esm/action/server/index.d.ts +9 -0
- package/dist/esm/action/server/index.d.ts.map +1 -0
- package/dist/esm/action/server/index.js +9 -0
- package/dist/esm/action/server/index.js.map +6 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interaction/AccessControlManager.d.ts +1 -1
- package/dist/esm/interaction/AccessControlManager.d.ts.map +1 -1
- package/dist/esm/interaction/AccessControlManager.js +2 -2
- package/dist/esm/interaction/AccessControlManager.js.map +1 -1
- package/dist/esm/interaction/AttributeDataEncoder.d.ts +1 -3
- package/dist/esm/interaction/AttributeDataEncoder.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts +5 -5
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionServer.d.ts +1 -1
- package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionServer.js +2 -2
- package/dist/esm/interaction/InteractionServer.js.map +1 -1
- package/dist/esm/interaction/ServerSubscription.d.ts +2 -2
- package/dist/esm/interaction/ServerSubscription.d.ts.map +1 -1
- package/dist/esm/interaction/ServerSubscription.js +0 -1
- package/dist/esm/interaction/ServerSubscription.js.map +1 -1
- package/dist/esm/mdns/MdnsScanner.d.ts +2 -2
- package/package.json +6 -6
- package/src/action/Interactable.ts +40 -0
- package/src/action/Val.ts +111 -0
- package/src/action/errors.ts +119 -0
- package/src/action/index.ts +13 -0
- package/src/action/protocols.ts +134 -0
- package/src/action/request/Invoke.ts +93 -0
- package/src/action/request/MalformedRequestError.ts +14 -0
- package/src/action/request/Read.ts +356 -0
- package/src/action/request/Specifier.ts +146 -0
- package/src/action/request/Subscribe.ts +54 -0
- package/src/action/request/Write.ts +13 -0
- package/src/action/request/index.ts +11 -0
- package/src/action/response/InvokeResult.ts +17 -0
- package/src/action/response/ReadResult.ts +89 -0
- package/src/action/response/SubscribeResult.ts +14 -0
- package/src/action/response/WriteResult.ts +13 -0
- package/src/action/response/index.ts +10 -0
- package/src/action/server/AccessControl.ts +494 -0
- package/src/action/server/AttributeResponse.ts +413 -0
- package/src/action/server/ServerInteraction.ts +64 -0
- package/src/action/server/index.ts +9 -0
- package/src/index.ts +1 -0
- package/src/interaction/AccessControlManager.ts +3 -3
- package/src/interaction/InteractionServer.ts +2 -3
- package/src/interaction/ServerSubscription.ts +0 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Write } from "#action/request/Write.js";
|
|
8
|
+
import type { CancelablePromise } from "#general";
|
|
9
|
+
import type { WriteResponse } from "#types";
|
|
10
|
+
|
|
11
|
+
export type WriteResult<T extends Write> = CancelablePromise<
|
|
12
|
+
T extends { suppressResponse: true } ? void : WriteResponse
|
|
13
|
+
>;
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Access, AccessLevel, DataModelPath, ElementTag, Schema, ValueModel } from "#model";
|
|
8
|
+
import { ClusterId, EndpointNumber, FabricIndex, StatusCode, SubjectId } from "#types";
|
|
9
|
+
import { InvokeError, ReadError, SchemaImplementationError, WriteError } from "../errors.js";
|
|
10
|
+
|
|
11
|
+
const cache = new WeakMap<Schema, AccessControl>();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Enforces access control for a specific schema.
|
|
15
|
+
*/
|
|
16
|
+
export interface AccessControl {
|
|
17
|
+
/**
|
|
18
|
+
* Operational access control metadata.
|
|
19
|
+
*/
|
|
20
|
+
limits: AccessControl.Limits;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Assert read is authorized.
|
|
24
|
+
*/
|
|
25
|
+
authorizeRead: AccessControl.Assertion;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Determine if read is authorized.
|
|
29
|
+
*/
|
|
30
|
+
mayRead: AccessControl.Verification;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Assert write is authorized.
|
|
34
|
+
*/
|
|
35
|
+
authorizeWrite: AccessControl.Assertion;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Determine if write is authorized.
|
|
39
|
+
*/
|
|
40
|
+
mayWrite: AccessControl.Verification;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Assert invoke is authorized.
|
|
44
|
+
*/
|
|
45
|
+
authorizeInvoke: AccessControl.Assertion;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Determine if invoke is authorized.
|
|
49
|
+
*/
|
|
50
|
+
mayInvoke: AccessControl.Verification;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Obtain an enforcer for specific schema.
|
|
55
|
+
*
|
|
56
|
+
* This is central to security. Implementation is explicit, all objects are involved are frozen and cache is stored as
|
|
57
|
+
* module-private.
|
|
58
|
+
*
|
|
59
|
+
* Pure function; returned value is cached.
|
|
60
|
+
*/
|
|
61
|
+
export function AccessControl(schema: Schema) {
|
|
62
|
+
let enforcer = cache.get(schema);
|
|
63
|
+
if (enforcer === undefined) {
|
|
64
|
+
enforcer = enforcerFor(schema);
|
|
65
|
+
}
|
|
66
|
+
return enforcer;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export namespace AccessControl {
|
|
70
|
+
/**
|
|
71
|
+
* Operational access control metadata for a schema.
|
|
72
|
+
*/
|
|
73
|
+
export interface Limits {
|
|
74
|
+
readonly readable: boolean;
|
|
75
|
+
readonly readLevel: AccessLevel;
|
|
76
|
+
|
|
77
|
+
readonly writable: boolean;
|
|
78
|
+
readonly writeLevel: AccessLevel;
|
|
79
|
+
|
|
80
|
+
readonly fabricScoped: boolean;
|
|
81
|
+
readonly fabricSensitive: boolean;
|
|
82
|
+
|
|
83
|
+
readonly timed: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A function that asserts access control requirements are met.
|
|
88
|
+
*/
|
|
89
|
+
export type Assertion = (session: Session, location: Location) => void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A function that returns true if access control requirements are met.
|
|
93
|
+
*/
|
|
94
|
+
export type Verification = (session: Session, location: Location) => boolean;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Metadata that varies with position in the data model.
|
|
98
|
+
*/
|
|
99
|
+
export interface Location {
|
|
100
|
+
/**
|
|
101
|
+
* The diagnostic path to the location.
|
|
102
|
+
*/
|
|
103
|
+
path: DataModelPath;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The owning endpoint.
|
|
107
|
+
*/
|
|
108
|
+
endpoint?: EndpointNumber;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The owning behavior.
|
|
112
|
+
*/
|
|
113
|
+
cluster?: ClusterId;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The fabric that owns the data subtree. Undefined or {@link FabricIndex.NO_FABRIC} disables fabric
|
|
117
|
+
* enforcement.
|
|
118
|
+
*/
|
|
119
|
+
owningFabric?: FabricIndex;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Authorization metadata that varies with session.
|
|
124
|
+
*/
|
|
125
|
+
export interface Session {
|
|
126
|
+
/**
|
|
127
|
+
* Determine whether authorized client has authority at a specific location.
|
|
128
|
+
*/
|
|
129
|
+
authorityAt(desiredAccessLevel: AccessLevel, location?: Location): Authority;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The fabric of the authorized client.
|
|
133
|
+
*/
|
|
134
|
+
readonly fabric?: FabricIndex;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The authenticated {@link SubjectId} for online sessions.
|
|
138
|
+
*/
|
|
139
|
+
readonly subject?: SubjectId;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Flag subject as a group rather than a peer.
|
|
143
|
+
*/
|
|
144
|
+
readonly isGroupSubject?: boolean;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* If this is true, fabric-scoped lists are filtered to the accessing fabric.
|
|
148
|
+
*/
|
|
149
|
+
readonly fabricFiltered?: boolean;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* If this is true a timed transaction is in effect.
|
|
153
|
+
*/
|
|
154
|
+
readonly timed?: boolean;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* If this is true then data access levels are not enforced. Datatypes and command-related access controls are
|
|
158
|
+
* active.
|
|
159
|
+
*/
|
|
160
|
+
readonly command?: boolean;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* If this is true then access levels are not enforced and all values are read/write. Datatypes are still
|
|
164
|
+
* enforced.
|
|
165
|
+
*
|
|
166
|
+
* Tracks "offline" rather than "online" because this makes the safer mode (full enforcement) the default.
|
|
167
|
+
*/
|
|
168
|
+
offline?: boolean;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Authority status.
|
|
173
|
+
*/
|
|
174
|
+
export enum Authority {
|
|
175
|
+
/**
|
|
176
|
+
* Authority is granted.
|
|
177
|
+
*/
|
|
178
|
+
Granted = 1,
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Insufficient privileges.
|
|
182
|
+
*/
|
|
183
|
+
Unauthorized = 2,
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Feature is restricted.
|
|
187
|
+
*/
|
|
188
|
+
Restricted = 3,
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
Object.freeze(AccessControl);
|
|
193
|
+
Object.freeze(AccessControl.Authority);
|
|
194
|
+
|
|
195
|
+
function enforcerFor(schema: Schema): AccessControl {
|
|
196
|
+
if (schema.tag === ElementTag.Command) {
|
|
197
|
+
return commandEnforcerFor(schema);
|
|
198
|
+
}
|
|
199
|
+
return dataEnforcerFor(schema);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function dataEnforcerFor(schema: Schema): AccessControl {
|
|
203
|
+
const limits = limitsFor(schema);
|
|
204
|
+
|
|
205
|
+
let mayRead: AccessControl.Verification = (session, location) => {
|
|
206
|
+
if (session.offline || session.command) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return session.authorityAt(limits.readLevel, location) === AccessControl.Authority.Granted;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
let mayWrite: AccessControl.Verification = (session, location) => {
|
|
214
|
+
if (session.offline || session.command) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return session.authorityAt(limits.writeLevel, location) === AccessControl.Authority.Granted;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
let authorizeRead: AccessControl.Assertion = (session, location) => {
|
|
222
|
+
if (session.offline || session.command) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (session.authorityAt(limits.readLevel, location) === AccessControl.Authority.Granted) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
throw new ReadError(location, "Permission denied", StatusCode.UnsupportedAccess);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
let authorizeWrite: AccessControl.Assertion = (session, location) => {
|
|
234
|
+
if (session.offline || session.command) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (session.authorityAt(limits.writeLevel, location) === AccessControl.Authority.Granted) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
throw new WriteError(location, "Permission denied", StatusCode.UnsupportedAccess);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
if (limits.timed) {
|
|
246
|
+
const wrappedAuthorizeWrite = authorizeWrite;
|
|
247
|
+
const wrappedMayWrite = mayWrite;
|
|
248
|
+
|
|
249
|
+
authorizeWrite = (session, location) => {
|
|
250
|
+
if (!session.offline && !session.timed) {
|
|
251
|
+
throw new WriteError(
|
|
252
|
+
location,
|
|
253
|
+
"Permission denied because interaction is not timed",
|
|
254
|
+
StatusCode.NeedsTimedInteraction,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
wrappedAuthorizeWrite?.(session, location);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
mayWrite = (session, location) => {
|
|
261
|
+
if (!session.offline && !session.timed) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return wrappedMayWrite(session, location);
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (limits.fabricSensitive) {
|
|
270
|
+
const wrappedAuthorizeRead = authorizeRead;
|
|
271
|
+
const wrappedMayRead = mayRead;
|
|
272
|
+
const wrappedAuthorizeWrite = authorizeWrite;
|
|
273
|
+
const wrappedMayWrite = mayWrite;
|
|
274
|
+
|
|
275
|
+
authorizeRead = (session, location) => {
|
|
276
|
+
if (session.offline || session.command) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (session.fabricFiltered) {
|
|
281
|
+
if (session.fabric === undefined) {
|
|
282
|
+
throw new ReadError(
|
|
283
|
+
location,
|
|
284
|
+
"Permission denied: No accessing fabric",
|
|
285
|
+
StatusCode.UnsupportedAccess,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (location?.owningFabric && location.owningFabric !== session.fabric) {
|
|
290
|
+
throw new ReadError(
|
|
291
|
+
location,
|
|
292
|
+
"Permission denied: Owning/accessing fabric mismatch",
|
|
293
|
+
StatusCode.UnsupportedAccess,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
wrappedAuthorizeRead(session, location);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
mayRead = (session, location) => {
|
|
302
|
+
if (session.offline || session.command) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (session.fabric === undefined) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (location?.owningFabric && location.owningFabric !== session.fabric) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return wrappedMayRead(session, location);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
authorizeWrite = (session, location) => {
|
|
318
|
+
if (session.offline || session.command) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (session.fabric === undefined) {
|
|
323
|
+
throw new WriteError(location, "Permission denied: No accessing fabric", StatusCode.UnsupportedAccess);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (location?.owningFabric && location.owningFabric !== session.fabric) {
|
|
327
|
+
throw new WriteError(location, "Permission denied: Owning/accessing fabric mismatch");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
wrappedAuthorizeWrite(session, location);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
mayWrite = (session, location) => {
|
|
334
|
+
if (session.offline || session.command) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (session.fabric === undefined) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (location?.owningFabric && location.owningFabric !== session.fabric) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return wrappedMayWrite(session, location);
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!limits.readable) {
|
|
351
|
+
authorizeRead = (session, location) => {
|
|
352
|
+
if (session.offline || session.command) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
throw new ReadError(location, "Permission defined: Value is write-only");
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
mayRead = session => {
|
|
360
|
+
return !!session.offline || !!session.command;
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!limits.writable) {
|
|
365
|
+
authorizeWrite = (session, location) => {
|
|
366
|
+
if (session.offline || session.command) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
throw new WriteError(location, "Permission denied: Value is read-only");
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
mayWrite = session => {
|
|
373
|
+
return !!session.offline || !!session.command;
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return Object.freeze({
|
|
378
|
+
limits,
|
|
379
|
+
authorizeRead,
|
|
380
|
+
mayRead,
|
|
381
|
+
authorizeWrite,
|
|
382
|
+
mayWrite,
|
|
383
|
+
|
|
384
|
+
authorizeInvoke(_session: AccessControl.Session, location: AccessControl.Location) {
|
|
385
|
+
throw new SchemaImplementationError(location, "Permission denied: Invoke request but non-command schema");
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
mayInvoke() {
|
|
389
|
+
return false;
|
|
390
|
+
},
|
|
391
|
+
} satisfies AccessControl);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function commandEnforcerFor(schema: Schema): AccessControl {
|
|
395
|
+
const limits = limitsFor(schema);
|
|
396
|
+
const timed = schema.effectiveAccess.timed;
|
|
397
|
+
const fabric = schema.effectiveAccess.fabric;
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
limits,
|
|
401
|
+
|
|
402
|
+
authorizeRead(_session, location) {
|
|
403
|
+
throw new SchemaImplementationError(location, "Permission denied: Read request but command schema");
|
|
404
|
+
},
|
|
405
|
+
|
|
406
|
+
mayRead() {
|
|
407
|
+
return false;
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
authorizeWrite(_session, location) {
|
|
411
|
+
throw new SchemaImplementationError(location, "Permission denied: Write request but command schema");
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
mayWrite() {
|
|
415
|
+
return false;
|
|
416
|
+
},
|
|
417
|
+
|
|
418
|
+
authorizeInvoke(session, location) {
|
|
419
|
+
if (session.offline) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!session.command) {
|
|
424
|
+
throw new InvokeError(location, "Invoke attempt without command context");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (timed && !session.timed) {
|
|
428
|
+
throw new InvokeError(
|
|
429
|
+
location,
|
|
430
|
+
"Invoke attempt without required timed context",
|
|
431
|
+
StatusCode.TimedRequestMismatch,
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (fabric && session.fabric === undefined) {
|
|
436
|
+
throw new WriteError(location, "Permission denied: No accessing fabric", StatusCode.UnsupportedAccess);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (session.authorityAt(limits.writeLevel, location) === AccessControl.Authority.Granted) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
throw new InvokeError(location, "Permission denied", StatusCode.UnsupportedAccess);
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
mayInvoke(session, location) {
|
|
447
|
+
if (session.offline) {
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (!session.command) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (timed && !session.timed) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (fabric && session.fabric === undefined) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return session.authorityAt(limits.writeLevel, location) === AccessControl.Authority.Granted;
|
|
464
|
+
},
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function limitsFor(schema: Schema) {
|
|
469
|
+
const access = schema.effectiveAccess;
|
|
470
|
+
const quality = schema instanceof ValueModel ? schema.effectiveQuality : undefined;
|
|
471
|
+
|
|
472
|
+
// Special handling for fixed values - we treat any property owned by a fixed value as also read-only
|
|
473
|
+
let fixed = quality?.fixed;
|
|
474
|
+
for (let s = schema.parent; !fixed && s instanceof ValueModel; s = s.parent) {
|
|
475
|
+
if (s.effectiveQuality.fixed) {
|
|
476
|
+
fixed = true;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const limits: AccessControl.Limits = Object.freeze({
|
|
481
|
+
readable: access.readable,
|
|
482
|
+
writable: access.writable && !fixed,
|
|
483
|
+
fabricScoped: access.fabric === Access.Fabric.Scoped || access.fabric === Access.Fabric.Sensitive,
|
|
484
|
+
fabricSensitive: access.fabric === Access.Fabric.Sensitive,
|
|
485
|
+
timed: access.timed === true,
|
|
486
|
+
|
|
487
|
+
// Official Matter defaults are View for read and Operate for write. However, the schema's effective access
|
|
488
|
+
// should already have these defaults. Here we just adopt minimum needed rights as a safe fallback access level.
|
|
489
|
+
readLevel: access.readPriv === undefined ? AccessLevel.View : Access.PrivilegeLevel[access.readPriv],
|
|
490
|
+
writeLevel: access.writePriv === undefined ? AccessLevel.Operate : Access.PrivilegeLevel[access.writePriv],
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
return limits;
|
|
494
|
+
}
|