Skip to content

Commit

Permalink
Merge pull request #20 from OpenSecretCloud/local-attestation-fix
Browse files Browse the repository at this point in the history
Fix local attestations
  • Loading branch information
AnthonyRonning authored Jan 31, 2025
2 parents 21741f4 + 6d190d1 commit 86c27fb
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 35 deletions.
68 changes: 36 additions & 32 deletions src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { encode } from "@stablelib/base64";
import { authenticatedApiCall, encryptedApiCall } from "./encryptedApi";

let API_URL = "http://localhost:3000";
let apiUrl = "";

export function setApiUrl(url: string) {
API_URL = url;
apiUrl = url;
}

export function getApiUrl(): string {
return apiUrl;
}

export type LoginResponse = {
Expand Down Expand Up @@ -43,7 +47,7 @@ export async function fetchLogin(
password: string
): Promise<LoginResponse> {
return encryptedApiCall<{ email: string; password: string }, LoginResponse>(
`${API_URL}/login`,
`${apiUrl}/login`,
"POST",
{ email, password }
);
Expand All @@ -54,7 +58,7 @@ export async function fetchGuestLogin(
password: string
): Promise<LoginResponse> {
return encryptedApiCall<{ id: string; password: string }, LoginResponse>(
`${API_URL}/login`,
`${apiUrl}/login`,
"POST",
{ id, password }
);
Expand All @@ -69,7 +73,7 @@ export async function fetchSignUp(
return encryptedApiCall<
{ email: string; password: string; inviteCode: string; name?: string | null },
LoginResponse
>(`${API_URL}/register`, "POST", {
>(`${apiUrl}/register`, "POST", {
email,
password,
inviteCode: inviteCode.toLowerCase(),
Expand All @@ -84,7 +88,7 @@ export async function fetchGuestSignUp(
return encryptedApiCall<
{ password: string; inviteCode: string },
LoginResponse
>(`${API_URL}/register`, "POST", {
>(`${apiUrl}/register`, "POST", {
password,
inviteCode: inviteCode.toLowerCase()
});
Expand All @@ -98,7 +102,7 @@ export async function refreshToken(): Promise<RefreshResponse> {

try {
const response = await encryptedApiCall<typeof refreshData, RefreshResponse>(
`${API_URL}/refresh`,
`${apiUrl}/refresh`,
"POST",
refreshData,
undefined,
Expand All @@ -116,7 +120,7 @@ export async function refreshToken(): Promise<RefreshResponse> {

export async function fetchUser(): Promise<UserResponse> {
return authenticatedApiCall<void, UserResponse>(
`${API_URL}/protected/user`,
`${apiUrl}/protected/user`,
"GET",
undefined,
"Failed to fetch user"
Expand All @@ -125,7 +129,7 @@ export async function fetchUser(): Promise<UserResponse> {

export async function fetchPut(key: string, value: string): Promise<string> {
return authenticatedApiCall<string, string>(
`${API_URL}/protected/kv/${key}`,
`${apiUrl}/protected/kv/${key}`,
"PUT",
value,
"Failed to put key-value pair"
Expand All @@ -134,7 +138,7 @@ export async function fetchPut(key: string, value: string): Promise<string> {

export async function fetchDelete(key: string): Promise<void> {
return authenticatedApiCall<void, void>(
`${API_URL}/protected/kv/${key}`,
`${apiUrl}/protected/kv/${key}`,
"DELETE",
undefined,
"Failed to delete key-value pair"
Expand All @@ -144,7 +148,7 @@ export async function fetchDelete(key: string): Promise<void> {
export async function fetchGet(key: string): Promise<string | undefined> {
try {
const data = await authenticatedApiCall<void, string>(
`${API_URL}/protected/kv/${key}`,
`${apiUrl}/protected/kv/${key}`,
"GET",
undefined,
"Failed to get key-value pair"
Expand All @@ -158,7 +162,7 @@ export async function fetchGet(key: string): Promise<string | undefined> {

export async function fetchList(): Promise<KVListItem[]> {
return authenticatedApiCall<void, KVListItem[]>(
`${API_URL}/protected/kv`,
`${apiUrl}/protected/kv`,
"GET",
undefined,
"Failed to list key-value pairs"
Expand All @@ -167,12 +171,12 @@ export async function fetchList(): Promise<KVListItem[]> {

export async function fetchLogout(refresh_token: string): Promise<void> {
const refreshData = { refresh_token };
return encryptedApiCall<typeof refreshData, void>(`${API_URL}/logout`, "POST", refreshData);
return encryptedApiCall<typeof refreshData, void>(`${apiUrl}/logout`, "POST", refreshData);
}

export async function verifyEmail(code: string): Promise<void> {
return encryptedApiCall<void, void>(
`${API_URL}/verify-email/${code}`,
`${apiUrl}/verify-email/${code}`,
"GET",
undefined,
undefined,
Expand All @@ -182,15 +186,15 @@ export async function verifyEmail(code: string): Promise<void> {

export async function requestNewVerificationCode(): Promise<void> {
return authenticatedApiCall<void, void>(
`${API_URL}/protected/request_verification`,
`${apiUrl}/protected/request_verification`,
"POST",
undefined,
"Failed to request new verification code"
);
}

export async function fetchAttestationDocument(nonce: string): Promise<string> {
const response = await fetch(`${API_URL}/attestation/${nonce}`);
const response = await fetch(`${apiUrl}/attestation/${nonce}`);
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
Expand All @@ -202,7 +206,7 @@ export async function keyExchange(
clientPublicKey: string,
nonce: string
): Promise<{ encrypted_session_key: string; session_id: string }> {
const response = await fetch(`${API_URL}/key_exchange`, {
const response = await fetch(`${apiUrl}/key_exchange`, {
method: "POST",
headers: {
"Content-Type": "application/json"
Expand All @@ -220,7 +224,7 @@ export async function keyExchange(
export async function requestPasswordReset(email: string, hashedSecret: string): Promise<void> {
const resetData = { email, hashed_secret: hashedSecret };
return encryptedApiCall<typeof resetData, void>(
`${API_URL}/password-reset/request`,
`${apiUrl}/password-reset/request`,
"POST",
resetData,
undefined,
Expand All @@ -241,7 +245,7 @@ export async function confirmPasswordReset(
new_password: newPassword
};
return encryptedApiCall<typeof confirmData, void>(
`${API_URL}/password-reset/confirm`,
`${apiUrl}/password-reset/confirm`,
"POST",
confirmData,
undefined,
Expand All @@ -255,7 +259,7 @@ export async function changePassword(currentPassword: string, newPassword: strin
new_password: newPassword
};
return authenticatedApiCall<typeof changePasswordData, void>(
`${API_URL}/protected/change_password`,
`${apiUrl}/protected/change_password`,
"POST",
changePasswordData,
"Failed to change password"
Expand All @@ -265,7 +269,7 @@ export async function changePassword(currentPassword: string, newPassword: strin
export async function initiateGitHubAuth(inviteCode?: string): Promise<GithubAuthResponse> {
try {
return await encryptedApiCall<{ invite_code?: string }, GithubAuthResponse>(
`${API_URL}/auth/github`,
`${apiUrl}/auth/github`,
"POST",
inviteCode ? { invite_code: inviteCode } : {},
undefined,
Expand All @@ -289,7 +293,7 @@ export async function handleGitHubCallback(
const callbackData = { code, state, invite_code: inviteCode };
try {
return await encryptedApiCall<typeof callbackData, LoginResponse>(
`${API_URL}/auth/github/callback`,
`${apiUrl}/auth/github/callback`,
"POST",
callbackData,
undefined,
Expand Down Expand Up @@ -332,7 +336,7 @@ export type GoogleAuthResponse = {
export async function initiateGoogleAuth(inviteCode?: string): Promise<GoogleAuthResponse> {
try {
return await encryptedApiCall<{ invite_code?: string }, GoogleAuthResponse>(
`${API_URL}/auth/google`,
`${apiUrl}/auth/google`,
"POST",
inviteCode ? { invite_code: inviteCode } : {},
undefined,
Expand All @@ -356,7 +360,7 @@ export async function handleGoogleCallback(
const callbackData = { code, state, invite_code: inviteCode };
try {
return await encryptedApiCall<typeof callbackData, LoginResponse>(
`${API_URL}/auth/google/callback`,
`${apiUrl}/auth/google/callback`,
"POST",
callbackData,
undefined,
Expand Down Expand Up @@ -398,7 +402,7 @@ export type PrivateKeyBytesResponse = {

export async function fetchPrivateKey(): Promise<PrivateKeyResponse> {
return authenticatedApiCall<void, PrivateKeyResponse>(
`${API_URL}/protected/private_key`,
`${apiUrl}/protected/private_key`,
"GET",
undefined,
"Failed to fetch private key"
Expand All @@ -422,8 +426,8 @@ export async function fetchPrivateKey(): Promise<PrivateKeyResponse> {
*/
export async function fetchPrivateKeyBytes(derivationPath?: string): Promise<PrivateKeyBytesResponse> {
const url = derivationPath
? `${API_URL}/protected/private_key_bytes?derivation_path=${encodeURIComponent(derivationPath)}`
: `${API_URL}/protected/private_key_bytes`;
? `${apiUrl}/protected/private_key_bytes?derivation_path=${encodeURIComponent(derivationPath)}`
: `${apiUrl}/protected/private_key_bytes`;

return authenticatedApiCall<void, PrivateKeyBytesResponse>(
url,
Expand Down Expand Up @@ -473,7 +477,7 @@ export async function signMessage(
): Promise<SignMessageResponse> {
const message_base64 = encode(message_bytes);
return authenticatedApiCall<SignMessageRequest, SignMessageResponse>(
`${API_URL}/protected/sign_message`,
`${apiUrl}/protected/sign_message`,
"POST",
{
message_base64,
Expand Down Expand Up @@ -508,8 +512,8 @@ export async function fetchPublicKey(
derivationPath?: string
): Promise<PublicKeyResponse> {
const url = derivationPath
? `${API_URL}/protected/public_key?algorithm=${algorithm}&derivation_path=${encodeURIComponent(derivationPath)}`
: `${API_URL}/protected/public_key?algorithm=${algorithm}`;
? `${apiUrl}/protected/public_key?algorithm=${algorithm}&derivation_path=${encodeURIComponent(derivationPath)}`
: `${apiUrl}/protected/public_key?algorithm=${algorithm}`;

return authenticatedApiCall<void, PublicKeyResponse>(
url,
Expand All @@ -531,7 +535,7 @@ export async function convertGuestToEmailAccount(
};

return authenticatedApiCall<typeof conversionData, void>(
`${API_URL}/protected/convert_guest`,
`${apiUrl}/protected/convert_guest`,
"POST",
conversionData,
"Failed to convert guest account"
Expand All @@ -548,7 +552,7 @@ export type ThirdPartyTokenResponse = {

export async function generateThirdPartyToken(audience: string): Promise<ThirdPartyTokenResponse> {
return authenticatedApiCall<ThirdPartyTokenRequest, ThirdPartyTokenResponse>(
`${API_URL}/protected/third_party_token`,
`${apiUrl}/protected/third_party_token`,
"POST",
{ audience },
"Failed to generate third party token"
Expand Down
7 changes: 5 additions & 2 deletions src/lib/attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { X509Certificate, X509ChainBuilder } from "@peculiar/x509";
import { decode, encode } from "@stablelib/base64";
import * as cbor from "cbor2";
import { z } from "zod";
import { fetchAttestationDocument } from "./api";
import { fetchAttestationDocument, getApiUrl } from "./api";
import awsRootCertDer from "../assets/aws_root.der";

// Assert that the root cert is not empty
Expand Down Expand Up @@ -257,10 +257,13 @@ async function fakeAuthenticate(
return zodParsed;
}

export async function verifyAttestation(nonce: string, apiUrl?: string): Promise<AttestationDocument> {
export async function verifyAttestation(nonce: string): Promise<AttestationDocument> {
try {
const attestationDocumentBase64 = await fetchAttestationDocument(nonce);

// Get the API URL from the API layer where it's already set
const apiUrl = getApiUrl();

// With a local backend we get a fake attestation document, so we'll just pretend to authenticate it
if (apiUrl && (
apiUrl === "http://127.0.0.1:3000" ||
Expand Down
2 changes: 1 addition & 1 deletion src/lib/getAttestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function getAttestation(forceRefresh?: boolean, apiUrl?: string): P
const attestationNonce = window.crypto.randomUUID();

console.log("Generated attestation nonce:", attestationNonce);
const document = await verifyAttestation(attestationNonce, apiUrl);
const document = await verifyAttestation(attestationNonce);

if (document && document.public_key) {
console.log("Attestation document verification succeeded");
Expand Down

0 comments on commit 86c27fb

Please sign in to comment.