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
4 changes: 4 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `isValidConnectionMode()` and `CONNECTION_MODES` for runtime validation of connection mode values

### Changed

- Add `validatePeerKey` method to `IKeyManager` interface for peer public key validation at handshake and resume time ([#70](https://github.com/MetaMask/mobile-wallet-protocol/pull/70))
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/domain/connection-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@
* 'trusted': A streamlined flow for same-device or trusted contexts that bypasses OTP.
* 'untrusted': The high-security flow requiring user verification via OTP.
*/
export type ConnectionMode = "trusted" | "untrusted";
export const CONNECTION_MODES = ["trusted", "untrusted"] as const;
export type ConnectionMode = (typeof CONNECTION_MODES)[number];

export function isValidConnectionMode(value: unknown): value is ConnectionMode {
return typeof value === "string" && CONNECTION_MODES.includes(value as ConnectionMode);
}
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { BaseClient } from "./base-client";
export { ClientState } from "./domain/client-state";
export type { ConnectionMode } from "./domain/connection-mode";
export { CONNECTION_MODES, type ConnectionMode, isValidConnectionMode } from "./domain/connection-mode";
export { CryptoError, ErrorCode, ProtocolError, SessionError, TransportError } from "./domain/errors";
export type { IKeyManager } from "./domain/key-manager";
export type { KeyPair } from "./domain/key-pair";
Expand Down
5 changes: 4 additions & 1 deletion packages/dapp-client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type IKeyManager,
type ISessionStore,
type ITransport,
isValidConnectionMode,
type Message,
type ProtocolMessage,
type Session,
Expand Down Expand Up @@ -107,9 +108,11 @@ export class DappClient extends BaseClient {
*/
public async connect(options: DappConnectOptions = {}): Promise<void> {
if (this.state !== ClientState.DISCONNECTED) throw new SessionError(ErrorCode.SESSION_INVALID_STATE, `Cannot connect when state is ${this.state}`);
this.state = ClientState.CONNECTING;

const { mode = "untrusted", initialPayload } = options;
if (!isValidConnectionMode(mode)) throw new SessionError(ErrorCode.SESSION_INVALID_STATE, `Invalid connection mode: "${String(mode)}"`);

this.state = ClientState.CONNECTING;
const { pendingSession, request } = this._createPendingSessionAndRequest(mode, initialPayload);
this.session = pendingSession;
this.emit("session_request", request);
Expand Down
5 changes: 4 additions & 1 deletion packages/wallet-client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type IKeyManager,
type ISessionStore,
type ITransport,
isValidConnectionMode,
type ProtocolMessage,
type Session,
SessionError,
Expand Down Expand Up @@ -77,11 +78,13 @@ export class WalletClient extends BaseClient {
*/
public async connect(options: { sessionRequest: SessionRequest }): Promise<void> {
if (this.state !== ClientState.DISCONNECTED) throw new SessionError(ErrorCode.SESSION_INVALID_STATE, `Cannot connect when state is ${this.state}`);
this.state = ClientState.CONNECTING;

const request = options.sessionRequest;
if (!isValidConnectionMode(request.mode)) throw new SessionError(ErrorCode.SESSION_INVALID_STATE, `Invalid connection mode: "${String(request.mode)}"`);
if (Date.now() > request.expiresAt) throw new SessionError(ErrorCode.REQUEST_EXPIRED, "Session request expired");

this.state = ClientState.CONNECTING;

const self = this;
const context: IConnectionHandlerContext = {
transport: this.transport,
Expand Down