327 lines
8.5 KiB
TypeScript
327 lines
8.5 KiB
TypeScript
import { translate as $l } from "@padloc/locale/src/translate";
|
|
import { Serializable } from "./encoding";
|
|
import { CryptoProvider } from "./crypto";
|
|
import { Err, ErrorCode } from "./error";
|
|
import { StubCryptoProvider } from "./stub-crypto-provider";
|
|
import { Storage, MemoryStorage } from "./storage";
|
|
import { AccountStatus, AuthPurpose, AuthType } from "./auth";
|
|
import { AccountProvisioning } from "./provisioning";
|
|
import { StartAuthRequestResponse } from "./api";
|
|
|
|
/**
|
|
* Object representing all information available for a given device.
|
|
*/
|
|
export class DeviceInfo extends Serializable {
|
|
/** Platform/Operating System running on the device */
|
|
platform: string = "";
|
|
|
|
/** OS version running on the device */
|
|
osVersion: string = "";
|
|
|
|
/** Unique device identifier */
|
|
id: string = "";
|
|
|
|
/** Padloc version installed on the device */
|
|
appVersion: string = "";
|
|
|
|
vendorVersion: string = "";
|
|
|
|
/** The user agent of the browser running the application */
|
|
userAgent: string = "";
|
|
|
|
/** The devices locale setting */
|
|
locale: string = "en";
|
|
|
|
/** The device manufacturer, if available */
|
|
manufacturer: string = "";
|
|
|
|
/** The device mode, if available */
|
|
model: string = "";
|
|
|
|
/** The browser the application was loaded in, if applicable */
|
|
browser: string = "";
|
|
|
|
/** The version of the browser the application was loaded in, if applicable */
|
|
browserVersion: string = "";
|
|
|
|
description: string = $l("Unknown Device");
|
|
|
|
constructor(props?: Partial<DeviceInfo>) {
|
|
super();
|
|
props && Object.assign(this, props);
|
|
}
|
|
}
|
|
|
|
export interface BiometricKeyStore {
|
|
isSupported(): Promise<boolean>;
|
|
getKey(id: string): Promise<Uint8Array>;
|
|
storeKey(id: string, key: Uint8Array): Promise<void>;
|
|
}
|
|
|
|
export class StubBiometricKeyStore {
|
|
async isSupported() {
|
|
return false;
|
|
}
|
|
getKey(_id: string): Promise<Uint8Array> {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
storeKey(_id: string, _key: Uint8Array): Promise<void> {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generic interface for various platform APIs
|
|
*/
|
|
export interface Platform {
|
|
/** Copies the given `text` to the system clipboard */
|
|
setClipboard(text: string): Promise<void>;
|
|
|
|
/** Retrieves the current text from the system clipboard */
|
|
getClipboard(): Promise<string>;
|
|
|
|
/** Get information about the current device */
|
|
getDeviceInfo(): Promise<DeviceInfo>;
|
|
|
|
crypto: CryptoProvider;
|
|
|
|
storage: Storage;
|
|
|
|
biometricKeyStore: BiometricKeyStore;
|
|
|
|
scanQR(): Promise<string>;
|
|
stopScanQR(): Promise<void>;
|
|
|
|
composeEmail(addr: string, subject: string, message: string): Promise<void>;
|
|
|
|
openExternalUrl(_url: string): void;
|
|
|
|
saveFile(name: string, type: string, contents: Uint8Array): Promise<void>;
|
|
|
|
readonly supportedAuthTypes: AuthType[];
|
|
|
|
registerAuthenticator(opts: {
|
|
purposes: AuthPurpose[];
|
|
type: AuthType;
|
|
data?: any;
|
|
device?: DeviceInfo;
|
|
}): Promise<string>;
|
|
|
|
startAuthRequest(opts: {
|
|
purpose: AuthPurpose;
|
|
type?: AuthType;
|
|
email?: string;
|
|
authenticatorId?: string;
|
|
authenticatorIndex?: number;
|
|
}): Promise<StartAuthRequestResponse>;
|
|
|
|
completeAuthRequest(req: StartAuthRequestResponse): Promise<{
|
|
token: string;
|
|
accountStatus: AccountStatus;
|
|
deviceTrusted: boolean;
|
|
provisioning: AccountProvisioning;
|
|
}>;
|
|
|
|
readonly platformAuthType: AuthType | null;
|
|
supportsPlatformAuthenticator(): Promise<boolean>;
|
|
registerPlatformAuthenticator(purposes: AuthPurpose[]): Promise<string>;
|
|
getPlatformAuthToken(_purpose: AuthPurpose[]): Promise<string>;
|
|
}
|
|
|
|
/**
|
|
* Stub implementation of the [[Platform]] interface. Useful for testing
|
|
*/
|
|
export class StubPlatform implements Platform {
|
|
crypto = new StubCryptoProvider();
|
|
storage: Storage = new MemoryStorage();
|
|
biometricKeyStore = new StubBiometricKeyStore();
|
|
|
|
get supportedAuthTypes(): AuthType[] {
|
|
return [];
|
|
}
|
|
|
|
async setClipboard(_val: string) {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
|
|
async getClipboard() {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
return "";
|
|
}
|
|
|
|
async getDeviceInfo() {
|
|
return new DeviceInfo();
|
|
}
|
|
|
|
async scanQR() {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
return "";
|
|
}
|
|
|
|
async stopScanQR() {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
|
|
async composeEmail(_addr: string, _subject: string, _message: string) {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
|
|
openExternalUrl(_url: string) {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
}
|
|
|
|
async saveFile(_name: string, _type: string, _contents: Uint8Array) {}
|
|
|
|
async registerAuthenticator(_opts: {
|
|
purposes: AuthPurpose[];
|
|
type: AuthType;
|
|
data?: any;
|
|
device?: DeviceInfo;
|
|
}): Promise<string> {
|
|
throw "Not implemented";
|
|
}
|
|
|
|
async startAuthRequest(_opts: {
|
|
purpose: AuthPurpose;
|
|
type?: AuthType | undefined;
|
|
email?: string | undefined;
|
|
authenticatorId?: string | undefined;
|
|
authenticatorIndex?: number | undefined;
|
|
}): Promise<StartAuthRequestResponse> {
|
|
throw new Error("Method not implemented.");
|
|
}
|
|
|
|
async completeAuthRequest(_req: StartAuthRequestResponse): Promise<{
|
|
token: string;
|
|
accountStatus: AccountStatus;
|
|
deviceTrusted: boolean;
|
|
provisioning: AccountProvisioning;
|
|
}> {
|
|
throw new Error("Method not implemented.");
|
|
}
|
|
|
|
readonly platformAuthType: AuthType | null = null;
|
|
|
|
async supportsPlatformAuthenticator() {
|
|
return false;
|
|
}
|
|
|
|
registerPlatformAuthenticator(_purpose: AuthPurpose[]): Promise<string> {
|
|
throw "Not implemented";
|
|
}
|
|
|
|
getPlatformAuthToken(_purpose: AuthPurpose[]): Promise<string> {
|
|
throw "Not implemented";
|
|
}
|
|
}
|
|
|
|
let platform: Platform = new StubPlatform();
|
|
|
|
/**
|
|
* Set the appropriate [[Platform]] implemenation for the current environment
|
|
*/
|
|
export function setPlatform(p: Platform) {
|
|
platform = p;
|
|
}
|
|
|
|
/**
|
|
* Get the current [[Platform]] implemenation
|
|
*/
|
|
export function getPlatform() {
|
|
return platform;
|
|
}
|
|
|
|
/** Copies the given `text` to the system clipboard */
|
|
export function getClipboard() {
|
|
return platform.getClipboard();
|
|
}
|
|
|
|
/** Retrieves the current text from the system clipboard */
|
|
export function setClipboard(val: string) {
|
|
return platform.setClipboard(val);
|
|
}
|
|
|
|
/** Get information about the current device */
|
|
export function getDeviceInfo() {
|
|
return platform.getDeviceInfo();
|
|
}
|
|
|
|
export function getCryptoProvider() {
|
|
return platform.crypto;
|
|
}
|
|
|
|
export function getStorage() {
|
|
return platform.storage;
|
|
}
|
|
|
|
export function scanQR() {
|
|
return platform.scanQR();
|
|
}
|
|
|
|
export function stopScanQR() {
|
|
return platform.stopScanQR();
|
|
}
|
|
|
|
export function composeEmail(addr: string, subject: string, message: string) {
|
|
return platform.composeEmail(addr, subject, message);
|
|
}
|
|
|
|
export function saveFile(name: string, type: string, contents: Uint8Array): Promise<void> {
|
|
return platform.saveFile(name, type, contents);
|
|
}
|
|
|
|
export function registerAuthenticator(opts: {
|
|
purposes: AuthPurpose[];
|
|
type: AuthType;
|
|
data?: any;
|
|
device?: DeviceInfo;
|
|
}): Promise<string> {
|
|
return platform.registerAuthenticator(opts);
|
|
}
|
|
|
|
export function startAuthRequest(opts: {
|
|
purpose: AuthPurpose;
|
|
type?: AuthType;
|
|
email?: string;
|
|
authenticatorId?: string;
|
|
authenticatorIndex?: number;
|
|
}): Promise<StartAuthRequestResponse> {
|
|
return platform.startAuthRequest(opts);
|
|
}
|
|
|
|
export function completeAuthRequest(req: StartAuthRequestResponse): Promise<{
|
|
token: string;
|
|
accountStatus: AccountStatus;
|
|
deviceTrusted: boolean;
|
|
provisioning: AccountProvisioning;
|
|
}> {
|
|
return platform.completeAuthRequest(req);
|
|
}
|
|
|
|
export async function authenticate(opts: {
|
|
purpose: AuthPurpose;
|
|
type?: AuthType;
|
|
email?: string;
|
|
authenticatorId?: string;
|
|
authenticatorIndex?: number;
|
|
}) {
|
|
const req = await startAuthRequest(opts);
|
|
return completeAuthRequest(req);
|
|
}
|
|
|
|
export function supportsPlatformAuthenticator() {
|
|
return platform.supportsPlatformAuthenticator();
|
|
}
|
|
|
|
export function registerPlatformAuthenticator(purposes: AuthPurpose[]) {
|
|
return platform.registerPlatformAuthenticator(purposes);
|
|
}
|
|
|
|
export function getPlatformAuthType() {
|
|
return platform.platformAuthType;
|
|
}
|
|
|
|
export function openExternalUrl(url: string) {
|
|
return platform.openExternalUrl(url);
|
|
}
|