Skip to content

Commit

Permalink
fix color validation, forbid external salt for other dapps, improve a…
Browse files Browse the repository at this point in the history
…dd asset fn
  • Loading branch information
seniorjoinu committed Mar 14, 2024
1 parent 2704c68 commit 59a0b88
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 46 deletions.
14 changes: 8 additions & 6 deletions apps/site/src/frontend/store/assets.tsx
Expand Up @@ -97,7 +97,9 @@ export function useTxnHistoryPageProps() {
return ctx.txnHistoryPageProps;
}

const PRE_DEFINED_ASSETS = Object.values(PRE_LISTED_TOKENS).map((it) => it.assetId);
const PRE_DEFINED_ASSETS: { assetId: string; name: string; symbol: string }[] = Object.values(PRE_LISTED_TOKENS).map(
(it) => ({ assetId: it.assetId, name: it.name, symbol: it.symbol }),
);

export function AssetsStore(props: IChildren) {
const [allAssetData, setAllAssetData] = createStore<AllAssetData>();
Expand Down Expand Up @@ -135,9 +137,9 @@ export function AssetsStore(props: IChildren) {

// CREATE PRE-DEFINED ASSETS
const assetsToCreate = [];
for (let assetId of PRE_DEFINED_ASSETS) {
if (fetchedAllAssetData[assetId]) continue;
assetsToCreate.push({ assetId });
for (let asset of PRE_DEFINED_ASSETS) {
if (fetchedAllAssetData[asset.assetId]) continue;
assetsToCreate.push(asset);
}
if (assetsToCreate.length > 0) {
await msq.addAsset({ assets: assetsToCreate });
Expand Down Expand Up @@ -201,9 +203,9 @@ export function AssetsStore(props: IChildren) {
}
};

const addAccount = async (assetId: string, assetName: string, symbol: string) => {
const addAccount = async (assetId: string) => {
const msq = _msq()!;
const name = await msq.addAssetAccount(assetId, assetName, symbol);
const name = await msq.addAssetAccount(assetId);

if (name === null) return;

Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/internal.ts
Expand Up @@ -96,10 +96,10 @@ export class InternalSnapClient {
return await this.inner._requestSnap(SNAP_METHODS.protected.icrc1.addAsset, req);
}

async addAssetAccount(assetId: string, assetName: string, assetSymbol: string): Promise<string | null> {
async addAssetAccount(assetId: string): Promise<string | null> {
this.checkInnerSet();

const body: IICRC1AddAssetAccountRequest = { assetId, name: assetName, symbol: assetSymbol };
const body: IICRC1AddAssetAccountRequest = { assetId };

return await this.inner._requestSnap(SNAP_METHODS.protected.icrc1.addAssetAccount, body);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/avatar.ts
@@ -1,5 +1,5 @@
import { Principal } from "@dfinity/principal";
import { escapeHtml } from "./types";
import { ZHexColorSanitized } from "./types";

/**
* Creates an SVG string for an avatar based on a given Principal object, with an optional background color.
Expand All @@ -13,7 +13,7 @@ import { escapeHtml } from "./types";
* @returns {string} A string representation of the SVG for the avatar, customized based on the Principal object.
*/
export function makeAvatarSvg(principal: Principal, bgColor: string = "#1E1F28"): string {
bgColor = escapeHtml(bgColor);
bgColor = ZHexColorSanitized.parse(bgColor);

const principalBytes = principalToBytes(principal);
const bodyColor = getBodyColor(principalBytes);
Expand Down
54 changes: 40 additions & 14 deletions packages/shared/src/index.ts
Expand Up @@ -149,119 +149,145 @@ export function originToHostname(origin: TOrigin): string {

export const PRE_LISTED_TOKENS: Record<
string,
{ name: string; assetId: string; logoSrc?: string; chargingAccountId?: string }
{ name: string; symbol: string; assetId: string; logoSrc?: string; chargingAccountId?: string }
> = {
"ryjl3-tyaaa-aaaaa-aaaba-cai": {
name: "ICP",
name: "Internet Computer",
symbol: "ICP",
assetId: "ryjl3-tyaaa-aaaaa-aaaba-cai",
logoSrc: "https://nns.ic0.app/_app/immutable/assets/icp-rounded.0be14f6b.svg",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"mxzaz-hqaaa-aaaar-qaada-cai": {
name: "ckBTC",
name: "Bitcoin",
symbol: "ckBTC",
assetId: "mxzaz-hqaaa-aaaar-qaada-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"ss2fx-dyaaa-aaaar-qacoq-cai": {
name: "ckETH",
name: "Ethereum",
symbol: "ckETH",
assetId: "ss2fx-dyaaa-aaaar-qacoq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"2ouva-viaaa-aaaaq-aaamq-cai": {
name: "CHAT",
name: "OpenChat",
symbol: "CHAT",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/3e3x2-xyaaa-aaaaq-aaalq-cai/logo.png",
assetId: "2ouva-viaaa-aaaaq-aaamq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"qbizb-wiaaa-aaaaq-aabwq-cai": {
name: "SONIC",
name: "Sonic",
symbol: "SONIC",
assetId: "qbizb-wiaaa-aaaaq-aabwq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"zfcdd-tqaaa-aaaaq-aaaga-cai": {
name: "SNS1",
name: "Dragginz",
symbol: "SNS1",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/zxeu2-7aaaa-aaaaq-aaafa-cai/logo.png",
assetId: "zfcdd-tqaaa-aaaaq-aaaga-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"jwcfb-hyaaa-aaaaj-aac4q-cai": {
name: "OGY",
name: "Origyn",
symbol: "OGY",
assetId: "jwcfb-hyaaa-aaaaj-aac4q-cai",
logoSrc: "https://msq.tech/ogy.svg",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"xsi2v-cyaaa-aaaaq-aabfq-cai": {
name: "MOD",
name: "Modclub",
symbol: "MOD",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/x4kx5-ziaaa-aaaaq-aabeq-cai/logo.png",
assetId: "xsi2v-cyaaa-aaaaq-aabfq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"4c4fd-caaaa-aaaaq-aaa3a-cai": {
name: "GHOST",
name: "ICGhost",
symbol: "GHOST",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/4m6il-zqaaa-aaaaq-aaa2a-cai/logo.png",
assetId: "4c4fd-caaaa-aaaaq-aaa3a-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"73mez-iiaaa-aaaaq-aaasq-cai": {
name: "KINIC",
name: "Kinic",
symbol: "KINIC",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/7jkta-eyaaa-aaaaq-aaarq-cai/logo.png",
assetId: "73mez-iiaaa-aaaaq-aaasq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"6rdgd-kyaaa-aaaaq-aaavq-cai": {
name: "HOT",
name: "Hot or Not",
symbol: "HOT",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/67bll-riaaa-aaaaq-aaauq-cai/logo.png",
assetId: "6rdgd-kyaaa-aaaaq-aaavq-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"uf2wh-taaaa-aaaaq-aabna-cai": {
name: "CAT",
name: "Catalyze",
symbol: "CAT",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/uly3p-iqaaa-aaaaq-aabma-cai/logo.png",
assetId: "uf2wh-taaaa-aaaaq-aabna-cai",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"vtrom-gqaaa-aaaaq-aabia-cai": {
name: "BOOM DAO",
symbol: "BOOM",
assetId: "vtrom-gqaaa-aaaaq-aabia-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/xjngq-yaaaa-aaaaq-aabha-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"tyyy3-4aaaa-aaaaq-aab7a-cai": {
name: "GOLD DAO",
name: "Gold DAO",
symbol: "GLDGov",
assetId: "tyyy3-4aaaa-aaaaq-aab7a-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/tw2vt-hqaaa-aaaaq-aab6a-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"rffwt-piaaa-aaaaq-aabqq-cai": {
name: "ICX",
symbol: "ICX",
assetId: "rffwt-piaaa-aaaaq-aabqq-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/u67kc-jyaaa-aaaaq-aabpq-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"f54if-eqaaa-aaaaq-aacea-cai": {
name: "Neutrinite",
symbol: "NTN",
assetId: "f54if-eqaaa-aaaaq-aacea-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/extk7-gaaaa-aaaaq-aacda-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"rxdbk-dyaaa-aaaaq-aabtq-cai": {
name: "Nuance",
symbol: "NUA",
assetId: "rxdbk-dyaaa-aaaaq-aabtq-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/rzbmc-yiaaa-aaaaq-aabsq-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"hvgxa-wqaaa-aaaaq-aacia-cai": {
name: "Sneed",
symbol: "SNEED",
assetId: "hvgxa-wqaaa-aaaaq-aacia-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/fp274-iaaaa-aaaaq-aacha-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"emww2-4yaaa-aaaaq-aacbq-cai": {
name: "TRAX",
symbol: "TRAX",
assetId: "emww2-4yaaa-aaaaq-aacbq-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/ecu3s-hiaaa-aaaaq-aacaq-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
"hhaaz-2aaaa-aaaaq-aacla-cai": {
name: "ICLighthouse DAO",
symbol: "ICL",
assetId: "hhaaz-2aaaa-aaaaq-aacla-cai",
logoSrc: "https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io/v1/sns/root/hjcnr-bqaaa-aaaaq-aacka-cai/logo.png",
chargingAccountId: "rmapb-pzxbf-4fimd-h33qy-aydfx-wxne6-64kqi-f6nwz-cfzyq-wf7tb-bqe",
},
};

/**
Expand Down
22 changes: 13 additions & 9 deletions packages/shared/src/types.ts
Expand Up @@ -32,6 +32,11 @@ export const ZNonEmptyStrSanitized = z.string().min(1).transform(escapeHtml);
export const ZPrincipalStrSanitized = z.string().regex(/^[0-9a-zA-Z]{1,5}(\-[0-9a-zA-Z]{1,5})*$/);
export const ZICRC1Subaccount = z.instanceof(Uint8Array);

/**
* A 6-digit hex color code, e.g. #12beef
*/
export const ZHexColorSanitized = z.string().regex(/^#[a-fA-F0-9]{6}$/);

/**
* Website origin, for example `https://google.com`
*/
Expand Down Expand Up @@ -117,8 +122,14 @@ export const ZStatistics = z.object({
data: ZStatisticsData,
});

export const ZAmountStrSanitized = z.string().regex(/^[0-9',\.]+$/);
const ZAssetNameSanitized = z.string().min(1).transform(escapeHtml);
export const ZTickerStrSanitized = z.string().regex(/^[A-Za-z0-9]+$/);

export type IAssetData = z.infer<typeof ZAssetData>;
export const ZAssetData = z.object({
name: ZAssetNameSanitized,
symbol: ZTickerStrSanitized,
accounts: z.record(ZNonEmptyStrSanitized, ZNonEmptyStrSanitized),
});

Expand Down Expand Up @@ -261,9 +272,6 @@ export const ZICRC1TransferRequest = z.object({
});
export type IICRC1TransferRequest = z.infer<typeof ZICRC1TransferRequest>;

export const ZAmountStrSanitized = z.string().regex(/^[0-9',\.]+$/);
export const ZTickerStrSanitized = z.string().regex(/^[A-Za-z0-9]+$/);

export const ZShowICRC1TransferConfirmRequest = z.object({
requestOrigin: ZOrigin,
from: ZPrincipalStrSanitized,
Expand All @@ -274,23 +282,19 @@ export const ZShowICRC1TransferConfirmRequest = z.object({
});
export type IShowICRC1TransferConfirmRequest = z.infer<typeof ZShowICRC1TransferConfirmRequest>;

const ZAssetNameSanitized = z.string().min(1).transform(escapeHtml);

export const ZICRC1AddAssetRequest = z.object({
assets: z.array(
z.object({
assetId: ZPrincipalStrSanitized,
name: z.optional(ZAssetNameSanitized),
symbol: z.optional(ZTickerStrSanitized),
name: ZAssetNameSanitized,
symbol: ZTickerStrSanitized,
}),
),
});
export type IICRC1AddAssetRequest = z.infer<typeof ZICRC1AddAssetRequest>;

export const ZICRC1AddAssetAccountRequest = z.object({
assetId: ZPrincipalStrSanitized,
name: ZAssetNameSanitized,
symbol: ZTickerStrSanitized,
});
export type IICRC1AddAssetAccountRequest = z.infer<typeof ZICRC1AddAssetAccountRequest>;

Expand Down
17 changes: 12 additions & 5 deletions packages/snap/src/protocols/icrc1.ts
Expand Up @@ -8,6 +8,7 @@ import {
bytesToHex,
fromCBOR,
originToHostname,
unreacheable,
zodParse,
} from "@fort-major/msq-shared";
import { divider, panel } from "@metamask/snaps-sdk";
Expand Down Expand Up @@ -71,7 +72,7 @@ export async function protected_handleAddAsset(bodyCBOR: string): Promise<IAsset
content: panel([
heading(`🔒 Confirm New Assets 🔒`),
text(`Are you sure you want to add the following tokens to your managed assets list?`),
...assetNames.map((it) => text(` - **${it}**`)),
...assetNames.map((it) => text(` **${it}**`)),
divider(),
text("**Confirm?** 🚀"),
]),
Expand All @@ -82,7 +83,7 @@ export async function protected_handleAddAsset(bodyCBOR: string): Promise<IAsset
}

const assetDataExternal: IAssetDataExternal[] = body.assets.map((it) => ({
accounts: Object.values(manager.addAsset(it.assetId).accounts),
accounts: Object.values(manager.addAsset(it.assetId, it.name, it.symbol).accounts),
}));

return assetDataExternal;
Expand All @@ -92,14 +93,20 @@ export async function protected_handleAddAssetAccount(bodyCBOR: string): Promise
const body = zodParse(ZICRC1AddAssetAccountRequest, fromCBOR(bodyCBOR));
const manager = await StateManager.make();

const assetData = manager.getAllAssetData()[body.assetId];

if (!assetData) {
unreacheable("attempt to add an account for an unknown asset");
}

const agreed = await snap.request({
method: "snap_dialog",
params: {
type: "confirmation",
content: panel([
heading(`🔒 Confirm New ${body.symbol} Account 🔒`),
text(`Are you sure you want to create a new **${body.name}** (**${body.symbol}**) token account?`),
text(`This will allow you to send and receive **${body.symbol}** tokens.`),
heading(`🔒 Confirm New ${assetData.symbol} Account 🔒`),
text(`Are you sure you want to create a new **${assetData.name}** (**${assetData.symbol}**) token account?`),
text(`This will allow you to send and receive **${assetData.symbol}** tokens.`),
divider(),
text("**Confirm?** 🚀"),
]),
Expand Down
10 changes: 8 additions & 2 deletions packages/snap/src/protocols/identity.ts
Expand Up @@ -83,8 +83,14 @@ export async function protected_handleIdentityLogin(bodyCBOR: string): Promise<t
}

const originData = await manager.getOriginData(body.toOrigin);
if (Object.keys(originData.masks).length === 0) {
unreacheable("login - no origin data found");

// check if the provided identityId points to an existing identity
if (body.withLinkedOrigin === undefined) {
if (!originData.masks[body.withIdentityId]) unreacheable("attempt to log in with an unknown identity");
} else {
const linkedOriginData = await manager.getOriginData(body.withLinkedOrigin);

if (!linkedOriginData.masks[body.withIdentityId]) unreacheable("attempt to log in with an unknown identity");
}

const timestamp = new Date().getTime();
Expand Down

0 comments on commit 59a0b88

Please sign in to comment.