Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 3 additions & 40 deletions packages/permission-controller/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,6 @@ Permission system concepts correspond to components of the MetaMask stack as fol
| Caveats | Caveat objects |
| Permission system | The `PermissionController` and its `json-rpc-engine` middleware |

### Target Keys and Target Names

When consuming or reading the `PermissionController`, you will encounter the concepts of "target keys" and "target names".
As described in the previous section, a permission grants a subject access to a restricted resource, called a _target_, which is some string.
Targets are referred to by consumers by their _names_, and internally (in the `PermissionController`) by their _keys_.
This distinction exists to enable namespaced targets, specifically namespaced JSON-RPC methods.

All targets have a single key.
If a target _is not_ namespaced, the key is identical to its name.
If a target _is_ namespaced, it may have any number of names, all of which are distinct from its key.
Permissions are always requested and invoked by their target name(s).

For example, for the non-namespaced restricted method `eth_accounts`, both the key and the name is `eth_accounts`.
On the other hand, the namespaced restricted method `wallet_getSecret_*` has the key `wallet_getSecret_*`, and any number of names where the `*` wildcard character is substituted for some valid string per the method implementation.

See [below](#construction) for a concrete example.

### Permission / Target Types

In practice, targets can be different things, necessitating distinct implementations in order to enforce the logic of the permission system.
Expand Down Expand Up @@ -121,14 +104,14 @@ const caveatSpecifications = {
},
};

// The property names of this object must be target keys.
// The property names of this object must be target names.
const permissionSpecifications = {
// This is a plain restricted method.
wallet_getSecretArray: {
// Every permission must have this field.
permissionType: PermissionType.RestrictedMethod,
// i.e. the restricted method name
targetKey: 'wallet_getSecretArray',
targetName: 'wallet_getSecretArray',
allowedCaveats: ['filterArrayResponse'],
// Every restricted method must specify its implementation in its
// specification.
Expand All @@ -139,31 +122,11 @@ const permissionSpecifications = {
},
},

// This is a namespaced restricted method.
'wallet_getSecret_*': {
permissionType: PermissionType.RestrictedMethod,
targetKey: 'wallet_getSecret_*',
methodImplementation: (
args: RestrictedMethodOptions<RestrictedMethodParameters>,
) => {
// The "method" is the string method name that was externally requested,
// and the "*" in the target key for this method will be replaced with
// some string whose value should affect the behavior of this method.
//
// "context" contains the origin of the requester and anything attached
// by the host during permission request processing.
const { method, context } = args;

const secretName = method.replace('wallet_getSecret_', '');
return context.getSecret(secretName);
},
},

// This is an endowment.
secretEndowment: {
permissionType: PermissionType.Endowment,
// Naming conventions for endowments are yet to be established.
targetKey: 'endowment:globals',
targetName: 'endowment:globals',
// This function will be called to retrieve the subject's endowment(s).
// Here we imagine that these are the names of globals that will be made
// available to a SES Compartment.
Expand Down
98 changes: 13 additions & 85 deletions packages/permission-controller/src/Permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,12 @@ export type PermissionConstraint = {
*
* See the README for details.
*
* @template TargetKey - They key of the permission target that the permission
* corresponds to.
* @template Name - The name of the permission that the target corresponds to.
* @template AllowedCaveat - A union of the allowed {@link Caveat} types
* for the permission.
*/
export type ValidPermission<
TargetKey extends TargetName,
Name extends TargetName,
AllowedCaveat extends CaveatConstraint,
> = PermissionConstraint & {
// TODO:TS4.4 Make optional
Expand All @@ -105,59 +104,9 @@ export type ValidPermission<
* A pointer to the resource that possession of the capability grants
* access to, for example a JSON-RPC method or endowment.
*/
readonly parentCapability: ExtractPermissionTargetNames<TargetKey>;
readonly parentCapability: Name;
};

/**
* A utility type for ensuring that the given permission target name conforms to
* our naming conventions.
*
* See the README for the distinction between target names and keys.
*/
type ValidTargetName<Name extends string> = Name extends `${string}*`
? never
: Name extends `${string}_`
? never
: Name;

/**
* A utility type for extracting permission target names from a union of target
* keys.
*
* See the README for the distinction between target names and keys.
*
* @template Key - The target key type to extract target names from.
*/
export type ExtractPermissionTargetNames<Key extends string> = ValidTargetName<
Key extends `${infer Base}_*` ? `${Base}_${string}` : Key
>;

/**
* Extracts the permission key of a particular name from a union of keys.
* An internal utility type used in {@link ExtractPermissionTargetKey}.
*
* @template Key - The target key type to extract from.
* @template Name - The name whose key to extract.
*/
type KeyOfTargetName<
Key extends string,
Name extends string,
> = Name extends ExtractPermissionTargetNames<Key> ? Key : never;

/**
* A utility type for finding the permission target key corresponding to a
* target name. In a way, the inverse of {@link ExtractPermissionTargetNames}.
*
* See the README for the distinction between target names and keys.
*
* @template Key - The target key type to extract from.
* @template Name - The name whose key to extract.
*/
export type ExtractPermissionTargetKey<
Key extends string,
Name extends string,
> = Key extends Name ? Key : Extract<Key, KeyOfTargetName<Key, Name>>;

/**
* Internal utility for extracting the members types of an array. The type
* evalutes to `never` if the specified type is the empty tuple or neither
Expand Down Expand Up @@ -392,22 +341,6 @@ export type PermissionSideEffect<
onFailure?: SideEffectHandler<Actions, Events>;
};

/**
* A utility type for ensuring that the given permission target key conforms to
* our naming conventions.
*
* See the README for the distinction between target names and keys.
*
* @template Key - The target key string to apply the constraint to.
*/
type ValidTargetKey<Key extends string> = Key extends `${string}_*`
? Key
: Key extends `${string}_`
? never
: Key extends `${string}*`
? never
: Key;

/**
* The different possible types of permissions.
*/
Expand Down Expand Up @@ -442,12 +375,9 @@ type PermissionSpecificationBase<Type extends PermissionType> = {
permissionType: Type;

/**
* The target resource of the permission. The shape of this string depends on
* the permission type. For example, a restricted method target key will
* consist of either a complete method name or the prefix of a namespaced
* method, e.g. `wallet_snap_*`.
* The name of the target resource of the permission.
*/
targetKey: string;
targetName: string;

/**
* An array of the caveat types that may be added to instances of this
Expand Down Expand Up @@ -549,7 +479,7 @@ type PermissionSpecificationBuilderOptions<
MethodHooks extends Record<string, unknown>,
ValidatorHooks extends Record<string, unknown>,
> = {
targetKey?: string;
targetName?: string;
allowedCaveats?: Readonly<NonEmptyArray<string>> | null;
factoryHooks?: FactoryHooks;
methodHooks?: MethodHooks;
Expand All @@ -575,7 +505,7 @@ export type PermissionSpecificationBuilder<
* {@link PermissionSpecificationBuilder} function and "hook name" objects.
*/
export type PermissionSpecificationBuilderExportConstraint = {
targetKey: string;
targetName: string;
specificationBuilder: PermissionSpecificationBuilder<
PermissionType,
PermissionSpecificationBuilderOptions<any, any, any>,
Expand All @@ -602,9 +532,7 @@ type ValidRestrictedMethodSpecification<
*/
export type ValidPermissionSpecification<
Specification extends PermissionSpecificationConstraint,
> = Specification['targetKey'] extends ValidTargetKey<
Specification['targetKey']
>
> = Specification['targetName'] extends TargetName
? Specification['permissionType'] extends PermissionType.Endowment
? Specification
: Specification['permissionType'] extends PermissionType.RestrictedMethod
Expand Down Expand Up @@ -644,8 +572,8 @@ export function hasSpecificationType<
export type PermissionSpecificationMap<
Specification extends PermissionSpecificationConstraint,
> = {
[TargetKey in Specification['targetKey']]: Specification extends {
targetKey: TargetKey;
[Name in Specification['targetName']]: Specification extends {
targetName: Name;
}
? Specification
: never;
Expand All @@ -656,13 +584,13 @@ export type PermissionSpecificationMap<
* permission specifications.
*
* @template Specification - The specification union type to extract from.
* @template TargetKey - The `targetKey` of the specification to extract.
* @template Name - The `targetName` of the specification to extract.
*/
export type ExtractPermissionSpecification<
Specification extends PermissionSpecificationConstraint,
TargetKey extends Specification['targetKey'],
Name extends Specification['targetName'],
> = Specification extends {
targetKey: TargetKey;
targetName: Name;
}
? Specification
: never;
Loading