// Copyright 2022 Luca Casonato. All rights reserved. MIT license. /** * Chrome Verified Access API Client for Deno * ========================================== * * API for Verified Access chrome extension to provide credential verification for chrome devices connecting to an enterprise network * * Docs: https://developers.google.com/chrome/verified-access * Source: https://googleapis.deno.dev/v1/verifiedaccess:v2.ts */ import { auth, CredentialsClient, GoogleAuth, request } from "/_/base@v1/mod.ts"; export { auth, GoogleAuth }; export type { CredentialsClient }; /** * API for Verified Access chrome extension to provide credential verification * for chrome devices connecting to an enterprise network */ export class VerifiedAccess { #client: CredentialsClient | undefined; #baseUrl: string; constructor(client?: CredentialsClient, baseUrl: string = "https://verifiedaccess.googleapis.com/") { this.#client = client; this.#baseUrl = baseUrl; } /** * Generates a new challenge. * */ async challengeGenerate(req: Empty): Promise { const url = new URL(`${this.#baseUrl}v2/challenge:generate`); const body = JSON.stringify(req); const data = await request(url.href, { client: this.#client, method: "POST", body, }); return deserializeChallenge(data); } /** * Verifies the challenge response. * */ async challengeVerify(req: VerifyChallengeResponseRequest): Promise { req = serializeVerifyChallengeResponseRequest(req); const url = new URL(`${this.#baseUrl}v2/challenge:verify`); const body = JSON.stringify(req); const data = await request(url.href, { client: this.#client, method: "POST", body, }); return data as VerifyChallengeResponseResult; } } /** * Antivirus information on a device. */ export interface Antivirus { /** * Output only. The state of the antivirus on the device. Introduced in * Chrome M136. */ readonly state?: | "STATE_UNSPECIFIED" | "MISSING" | "DISABLED" | "ENABLED"; } /** * Result message for VerifiedAccess.GenerateChallenge. */ export interface Challenge { /** * Generated challenge, the bytes representation of SignedData. */ challenge?: Uint8Array; } function serializeChallenge(data: any): Challenge { return { ...data, challenge: data["challenge"] !== undefined ? encodeBase64(data["challenge"]) : undefined, }; } function deserializeChallenge(data: any): Challenge { return { ...data, challenge: data["challenge"] !== undefined ? decodeBase64(data["challenge"] as string) : undefined, }; } /** * Properties of the CrowdStrike agent installed on a device. */ export interface CrowdStrikeAgent { /** * Output only. The Agent ID of the Crowdstrike agent. */ readonly agentId?: string; /** * Output only. The Customer ID to which the agent belongs to. */ readonly customerId?: string; } /** * The device signals as reported by Chrome. Unless otherwise specified, * signals are available on all platforms. */ export interface DeviceSignals { /** * Output only. Value of the AllowScreenLock policy on the device. See * https://chromeenterprise.google/policies/?policy=AllowScreenLock for more * details. Available on ChromeOS only. */ readonly allowScreenLock?: boolean; /** * Output only. Information about Antivirus software on the device. Available * on Windows only. */ readonly antivirus?: Antivirus; /** * Output only. Current version of the Chrome browser which generated this * set of signals. Example value: "107.0.5286.0". */ readonly browserVersion?: string; /** * Output only. Whether Chrome's built-in DNS client is used. The OS DNS * client is otherwise used. This value may be controlled by an enterprise * policy: https://chromeenterprise.google/policies/#BuiltInDnsClientEnabled. */ readonly builtInDnsClientEnabled?: boolean; /** * Output only. Whether access to the Chrome Remote Desktop application is * blocked via a policy. */ readonly chromeRemoteDesktopAppBlocked?: boolean; /** * Output only. Crowdstrike agent properties installed on the device, if any. * Available on Windows and MacOS only. */ readonly crowdStrikeAgent?: CrowdStrikeAgent; /** * Output only. Affiliation IDs of the organizations that are affiliated with * the organization that is currently managing the device. When the sets of * device and profile affiliation IDs overlap, it means that the organizations * managing the device and user are affiliated. To learn more about user * affiliation, visit * https://support.google.com/chrome/a/answer/12801245?ref_topic=9027936. */ readonly deviceAffiliationIds?: string[]; /** * Output only. Enrollment domain of the customer which is currently managing * the device. */ readonly deviceEnrollmentDomain?: string; /** * Output only. The name of the device's manufacturer. */ readonly deviceManufacturer?: string; /** * Output only. The name of the device's model. */ readonly deviceModel?: string; /** * Output only. The encryption state of the disk. On ChromeOS, the main disk * is always ENCRYPTED. */ readonly diskEncryption?: | "DISK_ENCRYPTION_UNSPECIFIED" | "DISK_ENCRYPTION_UNKNOWN" | "DISK_ENCRYPTION_DISABLED" | "DISK_ENCRYPTION_ENCRYPTED"; /** * Output only. The display name of the device, as defined by the user. */ readonly displayName?: string; /** * Hostname of the device. */ hostname?: string; /** * Output only. International Mobile Equipment Identity (IMEI) of the device. * Available on ChromeOS only. */ readonly imei?: string[]; /** * Output only. MAC addresses of the device. */ readonly macAddresses?: string[]; /** * Output only. Mobile Equipment Identifier (MEID) of the device. Available * on ChromeOS only. */ readonly meid?: string[]; /** * Output only. The type of the Operating System currently running on the * device. */ readonly operatingSystem?: | "OPERATING_SYSTEM_UNSPECIFIED" | "CHROME_OS" | "CHROMIUM_OS" | "WINDOWS" | "MAC_OS_X" | "LINUX"; /** * Output only. The state of the OS level firewall. On ChromeOS, the value * will always be ENABLED on regular devices and UNKNOWN on devices in * developer mode. Support for MacOS 15 (Sequoia) and later has been * introduced in Chrome M131. */ readonly osFirewall?: | "OS_FIREWALL_UNSPECIFIED" | "OS_FIREWALL_UNKNOWN" | "OS_FIREWALL_DISABLED" | "OS_FIREWALL_ENABLED"; /** * Output only. The current version of the Operating System. On Windows and * linux, the value will also include the security patch information. */ readonly osVersion?: string; /** * Output only. Whether the Password Protection Warning feature is enabled or * not. Password protection alerts users when they reuse their protected * password on potentially suspicious sites. This setting is controlled by an * enterprise policy: * https://chromeenterprise.google/policies/#PasswordProtectionWarningTrigger. * Note that the policy unset does not have the same effects as having the * policy explicitly set to `PASSWORD_PROTECTION_OFF`. */ readonly passwordProtectionWarningTrigger?: | "PASSWORD_PROTECTION_WARNING_TRIGGER_UNSPECIFIED" | "POLICY_UNSET" | "PASSWORD_PROTECTION_OFF" | "PASSWORD_REUSE" | "PHISHING_REUSE"; /** * Output only. Affiliation IDs of the organizations that are affiliated with * the organization that is currently managing the Chrome Profile’s user or * ChromeOS user. */ readonly profileAffiliationIds?: string[]; /** * Output only. Enrollment domain of the customer which is currently managing * the profile. */ readonly profileEnrollmentDomain?: string; /** * Output only. Whether Enterprise-grade (i.e. custom) unsafe URL scanning is * enabled or not. This setting may be controlled by an enterprise policy: * https://chromeenterprise.google/policies/#EnterpriseRealTimeUrlCheckMode */ readonly realtimeUrlCheckMode?: | "REALTIME_URL_CHECK_MODE_UNSPECIFIED" | "REALTIME_URL_CHECK_MODE_DISABLED" | "REALTIME_URL_CHECK_MODE_ENABLED_MAIN_FRAME"; /** * Output only. Safe Browsing Protection Level. That setting may be * controlled by an enterprise policy: * https://chromeenterprise.google/policies/#SafeBrowsingProtectionLevel. */ readonly safeBrowsingProtectionLevel?: | "SAFE_BROWSING_PROTECTION_LEVEL_UNSPECIFIED" | "INACTIVE" | "STANDARD" | "ENHANCED"; /** * Output only. The state of the Screen Lock password protection. On * ChromeOS, this value will always be ENABLED as there is not way to disable * requiring a password or pin when unlocking the device. */ readonly screenLockSecured?: | "SCREEN_LOCK_SECURED_UNSPECIFIED" | "SCREEN_LOCK_SECURED_UNKNOWN" | "SCREEN_LOCK_SECURED_DISABLED" | "SCREEN_LOCK_SECURED_ENABLED"; /** * Output only. Whether the device's startup software has its Secure Boot * feature enabled. Available on Windows only. */ readonly secureBootMode?: | "SECURE_BOOT_MODE_UNSPECIFIED" | "SECURE_BOOT_MODE_UNKNOWN" | "SECURE_BOOT_MODE_DISABLED" | "SECURE_BOOT_MODE_ENABLED"; /** * Output only. The serial number of the device. On Windows, this represents * the BIOS's serial number. Not available on most Linux distributions. */ readonly serialNumber?: string; /** * Output only. Whether the Site Isolation (a.k.a Site Per Process) setting * is enabled. That setting may be controlled by an enterprise policy: * https://chromeenterprise.google/policies/#SitePerProcess */ readonly siteIsolationEnabled?: boolean; /** * List of the addesses of all OS level DNS servers configured in the * device's network settings. */ systemDnsServers?: string[]; /** * Output only. Deprecated. The corresponding policy is now deprecated. * Whether Chrome is blocking third-party software injection or not. This * setting may be controlled by an enterprise policy: * https://chromeenterprise.google/policies/?policy=ThirdPartyBlockingEnabled. * Available on Windows only. */ readonly thirdPartyBlockingEnabled?: boolean; /** * Output only. The trigger which generated this set of signals. */ readonly trigger?: | "TRIGGER_UNSPECIFIED" | "TRIGGER_BROWSER_NAVIGATION" | "TRIGGER_LOGIN_SCREEN"; /** * Output only. Windows domain that the current machine has joined. Available * on Windows only. */ readonly windowsMachineDomain?: string; /** * Output only. Windows domain for the current OS user. Available on Windows * only. */ readonly windowsUserDomain?: string; } /** * A generic empty message that you can re-use to avoid defining duplicated * empty messages in your APIs. A typical example is to use it as the request or * the response type of an API method. For instance: service Foo { rpc * Bar(google.protobuf.Empty) returns (google.protobuf.Empty); } */ export interface Empty { } /** * Signed ChallengeResponse. */ export interface VerifyChallengeResponseRequest { /** * Required. The generated response to the challenge, the bytes * representation of SignedData. */ challengeResponse?: Uint8Array; /** * Optional. Service can optionally provide identity information about the * device or user associated with the key. For an EMK, this value is the * enrolled domain. For an EUK, this value is the user's email address. If * present, this value will be checked against contents of the response, and * verification will fail if there is no match. */ expectedIdentity?: string; } function serializeVerifyChallengeResponseRequest(data: any): VerifyChallengeResponseRequest { return { ...data, challengeResponse: data["challengeResponse"] !== undefined ? encodeBase64(data["challengeResponse"]) : undefined, }; } function deserializeVerifyChallengeResponseRequest(data: any): VerifyChallengeResponseRequest { return { ...data, challengeResponse: data["challengeResponse"] !== undefined ? decodeBase64(data["challengeResponse"] as string) : undefined, }; } /** * Result message for VerifiedAccess.VerifyChallengeResponse. The response * returned when successful for Managed profiles on Unmanaged browsers will NOT * have devicePermanentId, keyTrustLevel, virtualDeviceId and customerId fields. * Managed profiles will INSTEAD have the profileCustomerId, virtualProfileId, * profilePermanentId and profileKeyTrustLevel fields. */ export interface VerifyChallengeResponseResult { /** * Output only. Attested device ID (ADID). */ readonly attestedDeviceId?: string; /** * Output only. Unique customer id that this device belongs to, as defined by * the Google Admin SDK at * https://developers.google.com/admin-sdk/directory/v1/guides/manage-customers */ readonly customerId?: string; /** * Output only. Device enrollment id for ChromeOS devices. */ readonly deviceEnrollmentId?: string; /** * Output only. Device permanent id is returned in this field (for the * machine response only). */ readonly devicePermanentId?: string; /** * Output only. Deprecated. Device signal in json string representation. * Prefer using `device_signals` instead. */ readonly deviceSignal?: string; /** * Output only. Device signals. */ readonly deviceSignals?: DeviceSignals; /** * Output only. Device attested key trust level. */ readonly keyTrustLevel?: | "KEY_TRUST_LEVEL_UNSPECIFIED" | "CHROME_OS_VERIFIED_MODE" | "CHROME_OS_DEVELOPER_MODE" | "CHROME_BROWSER_HW_KEY" | "CHROME_BROWSER_OS_KEY" | "CHROME_BROWSER_NO_KEY"; /** * Output only. Unique customer id that this profile belongs to, as defined * by the Google Admin SDK at * https://developers.google.com/admin-sdk/directory/v1/guides/manage-customers */ readonly profileCustomerId?: string; /** * Output only. Profile attested key trust level. */ readonly profileKeyTrustLevel?: | "KEY_TRUST_LEVEL_UNSPECIFIED" | "CHROME_OS_VERIFIED_MODE" | "CHROME_OS_DEVELOPER_MODE" | "CHROME_BROWSER_HW_KEY" | "CHROME_BROWSER_OS_KEY" | "CHROME_BROWSER_NO_KEY"; /** * Output only. The unique server-side ID of a profile on the device. */ readonly profilePermanentId?: string; /** * Output only. Certificate Signing Request (in the SPKAC format, base64 * encoded) is returned in this field. This field will be set only if device * has included CSR in its challenge response. (the option to include CSR is * now available for both user and machine responses) */ readonly signedPublicKeyAndChallenge?: string; /** * Output only. Virtual device id of the device. The definition of virtual * device id is platform-specific. */ readonly virtualDeviceId?: string; /** * Output only. The client-provided ID of a profile on the device. */ readonly virtualProfileId?: string; } function decodeBase64(b64: string): Uint8Array { const binString = atob(b64); const size = binString.length; const bytes = new Uint8Array(size); for (let i = 0; i < size; i++) { bytes[i] = binString.charCodeAt(i); } return bytes; } const base64abc = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"]; /** * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727 * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation * @param data */ function encodeBase64(uint8: Uint8Array): string { let result = "", i; const l = uint8.length; for (i = 2; i < l; i += 3) { result += base64abc[uint8[i - 2] >> 2]; result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)]; result += base64abc[uint8[i] & 0x3f]; } if (i === l + 1) { // 1 octet yet to write result += base64abc[uint8[i - 2] >> 2]; result += base64abc[(uint8[i - 2] & 0x03) << 4]; result += "=="; } if (i === l) { // 2 octets yet to write result += base64abc[uint8[i - 2] >> 2]; result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; result += base64abc[(uint8[i - 1] & 0x0f) << 2]; result += "="; } return result; }