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
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Stellar Custom Wallet",
"version": "0.1.0",
"version": "0.1.1",
"description": "A Stellar wallet with custom capabilities built with Deno and React.",
"permissions": ["storage"],
"host_permissions": ["https://*/*", "http://localhost/*"],
Expand Down
31 changes: 20 additions & 11 deletions src/background/dev-seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
getRpcServer,
} from "@/background/contexts/chain/network.ts";
import { PrivacyProviderClient } from "@/background/services/privacy-provider-client.ts";
import { extractPpPubkeyFromUrl } from "@/background/services/pp-url.ts";

import { checkAccountActivationStatus } from "@/background/contexts/chain/account-activation.ts";
import { TransactionBuilder } from "@stellar/stellar-sdk";
Expand Down Expand Up @@ -241,23 +242,24 @@ export async function applyDevSeed(): Promise<void> {
);
const existingUrls = new Set(channel?.providers.map((p) => p.url) ?? []);

// SEED_PROVIDERS entries are `name=url|pubkey`. The pubkey segment is
// required for per-PP URL paths; if missing the entry is skipped.
// SEED_PROVIDERS entries are `name=url`. The URL must end in the PP's
// Stellar pubkey (extractPpPubkeyFromUrl validates at call-time); entries
// whose URL doesn't parse are silently skipped here.
const providerEntries = __SEED_PROVIDERS__.split(",").map((entry) => {
const eqIdx = entry.indexOf("=");
const rhs = entry.slice(eqIdx + 1).trim();
const [url, pubkey] = rhs.split("|").map((s) => s.trim());
return { name: entry.slice(0, eqIdx).trim(), url, pubkey: pubkey ?? "" };
return {
name: entry.slice(0, eqIdx).trim(),
url: entry.slice(eqIdx + 1).trim(),
};
});

for (const { name, url, pubkey } of providerEntries) {
if (!url || !pubkey || existingUrls.has(url)) continue;
for (const { name, url } of providerEntries) {
if (!url || existingUrls.has(url)) continue;
const providerId = crypto.randomUUID();
privateChannels.addProvider(network, channelId, {
id: providerId,
name,
url,
pubkey,
});
if (!firstProviderId) firstProviderId = providerId;
console.log("[dev-seed] Provider added:", name, url);
Expand All @@ -280,7 +282,7 @@ export async function applyDevSeed(): Promise<void> {
console.log("[dev-seed] Auto-connecting to provider:", provider.name);

// Get auth challenge
const client = new PrivacyProviderClient(provider.url, provider.pubkey);
const client = new PrivacyProviderClient(provider.url);
const challenge = await client.getAuthChallenge(publicKey);

// Sign the challenge directly using the mnemonic
Expand All @@ -296,8 +298,14 @@ export async function applyDevSeed(): Promise<void> {
transaction.sign(keypair);
const signedXdr = transaction.toXDR();

// Submit signed challenge
const authResponse = await client.postAuth(signedXdr);
// Submit signed challenge (PP-aware verify body)
const extracted = extractPpPubkeyFromUrl(provider.url);
if (!extracted) {
throw new Error(
`dev-seed provider URL missing pubkey path segment: ${provider.url}`,
);
}
const authResponse = await client.postAuth(signedXdr, extracted.pubkey);

// Save session
const expiresAt = Date.now() + 24 * 60 * 60 * 1000;
Expand All @@ -310,6 +318,7 @@ export async function applyDevSeed(): Promise<void> {
token: authResponse.token,
expiresAt,
entityStatus: authResponse.entityStatus,
kycSubmissionUrl: authResponse.kycSubmissionUrl,
},
);
await privateChannels.setSelectedProvider(
Expand Down
2 changes: 0 additions & 2 deletions src/background/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import {
handlePrepareWithdraw,
handleWithdraw,
} from "@/background/handlers/private/withdraw.ts";
import { handleSubmitEntityKyc } from "@/background/handlers/private/submit-entity-kyc.ts";
import {
ensureSessionHydrated,
isUnlocked,
Expand Down Expand Up @@ -117,7 +116,6 @@ const handlers: HandlerMap = {
[MessageType.PrepareSend]: handlePrepareSend,
[MessageType.Withdraw]: handleWithdraw,
[MessageType.PrepareWithdraw]: handlePrepareWithdraw,
[MessageType.SubmitEntityKyc]: handleSubmitEntityKyc,
};

browser.runtime.onMessage.addListener(
Expand Down
16 changes: 15 additions & 1 deletion src/background/handlers/private/add-privacy-provider.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import { MessageFor, MessageType, ResponseFor } from "@/background/messages.ts";
import { privateChannels } from "@/background/session.ts";
import { extractPpPubkeyFromUrl } from "@/background/services/pp-url.ts";

export const handleAddPrivacyProvider = async (
message: MessageFor<MessageType.AddPrivacyProvider>,
): Promise<ResponseFor<MessageType.AddPrivacyProvider>> => {
try {
// Authoritative URL shape validation: the URL must encode the PP's
// Stellar pubkey as its last path segment. The popup form does a soft
// check first; the background is the gate.
if (!extractPpPubkeyFromUrl(message.url)) {
return {
type: MessageType.AddPrivacyProvider,
ok: false,
error: {
code: "UNKNOWN",
message:
"Provider URL must end with the PP's Stellar public key (e.g. https://provider-x.example/G…).",
},
};
}
const providerId = crypto.randomUUID();
privateChannels.addProvider(message.network, message.channelId, {
id: providerId,
name: message.name,
url: message.url,
pubkey: message.pubkey,
});

await privateChannels.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export type AddPrivacyProviderRequest = {
channelId: string;
name: string;
url: string;
pubkey: string;
};

export type AddPrivacyProviderResponse =
Expand Down
19 changes: 14 additions & 5 deletions src/background/handlers/private/connect-privacy-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MessageType } from "@/background/messages.ts";
import type { Handler } from "@/background/messages.ts";
import { privateChannels, signingManager } from "@/background/session.ts";
import { PrivacyProviderClient } from "@/background/services/privacy-provider-client.ts";
import { extractPpPubkeyFromUrl } from "@/background/services/pp-url.ts";

export const handleConnectPrivacyProvider: Handler<
MessageType.ConnectPrivacyProvider
Expand All @@ -10,14 +11,20 @@ export const handleConnectPrivacyProvider: Handler<
channelId,
providerId,
providerUrl,
providerPubkey,
accountId,
publicKey,
network,
} = message;

const extracted = extractPpPubkeyFromUrl(providerUrl);
if (!extracted) {
throw new Error(
`Provider URL has no pubkey path segment: ${providerUrl}. Re-add the provider with the full URL ending in its Stellar public key.`,
);
}

// 1. Get Authentication Challenge from Provider
const client = new PrivacyProviderClient(providerUrl, providerPubkey);
const client = new PrivacyProviderClient(providerUrl);
const challenge = await client.getAuthChallenge(publicKey);

// 2. Create Signing Request
Expand All @@ -34,8 +41,8 @@ export const handleConnectPrivacyProvider: Handler<
try {
const signedXdr = await signingManager.waitForResult(request.id);

// 4. Submit Signed Challenge to Provider
const authResponse = await client.postAuth(signedXdr);
// 4. Submit Signed Challenge to Provider (PP-aware verify body)
const authResponse = await client.postAuth(signedXdr, extracted.pubkey);

// Validate token was received
if (!authResponse.token || typeof authResponse.token !== "string") {
Expand All @@ -58,6 +65,7 @@ export const handleConnectPrivacyProvider: Handler<
token: authResponse.token,
expiresAt,
entityStatus: authResponse.entityStatus,
kycSubmissionUrl: authResponse.kycSubmissionUrl,
},
);

Expand All @@ -66,7 +74,8 @@ export const handleConnectPrivacyProvider: Handler<
channelId,
providerId,
accountId,
hasToken: !!authResponse.token,
entityStatus: authResponse.entityStatus,
hasKycUrl: authResponse.kycSubmissionUrl !== null,
});

// 6. Auto-select the provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export type ConnectPrivacyProviderRequest = {
channelAddress: string;
providerId: string;
providerUrl: string;
providerPubkey: string;
accountId: string;
publicKey: string;
network: ChainNetwork;
Expand Down
2 changes: 1 addition & 1 deletion src/background/handlers/private/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ async function submitPreparedOperations(
}

// Submit bundle to provider
const client = new PrivacyProviderClient(provider.url, provider.pubkey);
const client = new PrivacyProviderClient(provider.url);
try {
const result = await client.submitBundle({
token: session.token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ export const handleGetPrivacyProviderAuthChallenge: Handler<
> = async (message) => {
const { providerUrl, publicKey } = message;

// SEP-10 challenge is global (not per-PP), so an empty pubkey is fine here.
const client = new PrivacyProviderClient(providerUrl, "");
const client = new PrivacyProviderClient(providerUrl);
const response = await client.getAuthChallenge(publicKey);

return {
Expand Down
2 changes: 1 addition & 1 deletion src/background/handlers/private/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ async function submitPreparedOperations(
}

// Submit bundle to provider
const client = new PrivacyProviderClient(provider.url, provider.pubkey);
const client = new PrivacyProviderClient(provider.url);
try {
const result = await client.submitBundle({
token: session.token,
Expand Down
127 changes: 0 additions & 127 deletions src/background/handlers/private/submit-entity-kyc.ts

This file was deleted.

21 changes: 0 additions & 21 deletions src/background/handlers/private/submit-entity-kyc.types.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/background/handlers/private/withdraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ async function submitPreparedOperations(
}

// Submit bundle to provider
const client = new PrivacyProviderClient(provider.url, provider.pubkey);
const client = new PrivacyProviderClient(provider.url);
try {
const result = await client.submitBundle({
token: session.token,
Expand Down
Loading
Loading