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
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
.siweRiskWarningContainer {
.riskWarningContainer {
display: flex;
align-items: center;
justify-content: center;
}

.siweRiskWarningBox {
.riskWarningBox {
display: flex;
padding: 6px 8px;
justify-content: center;
Expand All @@ -19,10 +19,10 @@
background-color: var(--bg-warning-primary);
}

.siweRiskWarningCheckBoxContainer {
.riskWarningCheckBoxContainer {
gap: 6px;
}

.siweRiskWarningCheckBoxInputContainerClassName {
.riskWarningCheckBoxInputContainerClassName {
padding-top: 0px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import type { FC } from "react";
import { Checkbox } from "@oko-wallet/oko-common-ui/checkbox";
import { Typography } from "@oko-wallet/oko-common-ui/typography";

import styles from "./siwe_risk_warning_box.module.scss";
import styles from "./risk_warning.module.scss";

interface SiweRiskWarningCheckBoxProps {
interface RiskWarningCheckBoxProps {
checked: boolean;
onChange: (isValidSiweMessage: boolean) => void;
onChange: (checked: boolean) => void;
}
export const SiweRiskWarningCheckBox: FC<SiweRiskWarningCheckBoxProps> = ({

export const RiskWarningCheckBox: FC<RiskWarningCheckBoxProps> = ({
checked,
onChange,
}) => {
return (
<div className={styles.siweRiskWarningContainer}>
<div className={styles.riskWarningContainer}>
<Checkbox
id="siwe-message-checkbox"
id="sign-in-message-checkbox"
checked={checked}
onChange={onChange}
label="I understand the risk and would like to proceed."
Expand All @@ -24,18 +25,18 @@ export const SiweRiskWarningCheckBox: FC<SiweRiskWarningCheckBoxProps> = ({
size: "xs",
weight: "medium",
}}
checkboxContainerClassName={styles.siweRiskWarningCheckBoxContainer}
checkboxContainerClassName={styles.riskWarningCheckBoxContainer}
checkBoxInputContainerClassName={
styles.siweRiskWarningCheckBoxInputContainerClassName
styles.riskWarningCheckBoxInputContainerClassName
}
/>
</div>
);
};

export const SiweRiskWarningBox = () => {
export const RiskWarningBox: FC = () => {
return (
<div className={styles.siweRiskWarningBox}>
<div className={styles.riskWarningBox}>
<Typography size="xs" color="warning-primary" weight="medium">
The URL requesting your signature differs from the current website. This
may indicate a potential security risk.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Common utilities for Sign In With X (SIWE/SIWS) message verification
*/

export const ALLOW_PROTOCOLS = ["https:"];
export const BYPASS_HOSTS = ["localhost"];

/**
* Verify that the sign-in message origin matches the request origin
*/
export function verifySignInOrigin(
domain: string,
uri: string | undefined,
origin: string,
): boolean {
try {
const {
origin: originByPayload,
protocol: protocolByPayload,
host: hostByPayload,
} = new URL(origin);

// Check domain matches
if (hostByPayload !== domain) {
return false;
}

// Check URI if provided
if (uri) {
const { origin: originByUri, protocol: protocolByUri } = new URL(uri);

if (originByPayload !== originByUri) {
return false;
}

// If scheme is not HTTPS, return false (when hostname is not localhost)
if (
!BYPASS_HOSTS.includes(hostByPayload.split(":")[0]) &&
(!ALLOW_PROTOCOLS.includes(protocolByPayload) ||
!ALLOW_PROTOCOLS.includes(protocolByUri))
) {
return false;
}
} else {
// No URI, just check protocol
if (
!BYPASS_HOSTS.includes(hostByPayload.split(":")[0]) &&
!ALLOW_PROTOCOLS.includes(protocolByPayload)
) {
return false;
}
}
} catch (error) {
console.error(error);
return false;
}

return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import {
SignerAddressOrEmailView,
} from "@oko-wallet-attached/components/modal_variants/common/metadata_content/signer_address_or_email/signer_address_or_email";

interface SignerAddressOrEmailProps {
interface SignerInfoProps {
signer: string;
origin: string;
initialViewType?: "View Address" | "Login Info";
}

export const SignerAddressOrEmailForSiwe: FC<SignerAddressOrEmailProps> = ({
export const SignerInfo: FC<SignerInfoProps> = ({
signer,
origin,
initialViewType = "View Address",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
width: 100%;
word-break: break-all;
word-wrap: break-word;
overflow-wrap: break-word;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
verifySiweMessage,
} from "@oko-wallet-attached/components/modal_variants/eth/siwe_message";
import { EthereumSiweSignatureContent } from "@oko-wallet-attached/components/modal_variants/eth/arbitrary_sig/siwe_sig/make_siwe_signature_content";
import { SiweRiskWarningCheckBox } from "@oko-wallet-attached/components/modal_variants/eth/arbitrary_sig/siwe_sig/siwe_risk_warning_box";
import { RiskWarningCheckBox } from "@oko-wallet-attached/components/modal_variants/common/risk_warning/risk_warning";

export const MakeArbitrarySigModal: FC<MakeArbitrarySigModalProps> = ({
getIsAborted,
Expand Down Expand Up @@ -74,14 +74,14 @@ export const MakeArbitrarySigModal: FC<MakeArbitrarySigModalProps> = ({
)}
</div>

<Spacing height={!!siweMessage ? 12 : 20} />
<Spacing height={20} />
{!hasOnChainSchema && <ArbitrarySignatureDesc />}

<Spacing height={8} />

{siweMessage && !isValidSiweMessage && (
<>
<SiweRiskWarningCheckBox
<RiskWarningCheckBox
checked={isSiweRiskWarningChecked}
onChange={setIsSiweRiskWarningChecked}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { Typography } from "@oko-wallet/oko-common-ui/typography";
import type { Theme } from "@oko-wallet/oko-common-ui/theme";
import type { FC } from "react";

import styles from "./ethereum_siwe_signature_content.module.scss";
import styles from "@oko-wallet-attached/components/modal_variants/common/sign_in_content/sign_in_content.module.scss";
import {
getSiweMessage,
verifySiweMessage,
} from "@oko-wallet-attached/components/modal_variants/eth/siwe_message";
import { SiweSigTitleBadge } from "@oko-wallet-attached/components/modal_variants/eth/arbitrary_sig/siwe_sig/siwe_sig_title_badge";
import { SignerAddressOrEmailForSiwe } from "@oko-wallet-attached/components/modal_variants/eth/arbitrary_sig/siwe_sig/signer_address_or_email_for_siwe";
import { SignerInfo } from "@oko-wallet-attached/components/modal_variants/common/signer_info";
import { MakeSignatureRawCodeBlockContainer } from "@oko-wallet-attached/components/modal_variants/common/make_signature/make_sig_modal_code_block_container";
import { MakeSignatureRawCodeBlock } from "@oko-wallet-attached/components/modal_variants/common/make_signature/make_sig_modal_code_block";
import { SiweRiskWarningBox } from "@oko-wallet-attached/components/modal_variants/eth/arbitrary_sig/siwe_sig/siwe_risk_warning_box";
import { RiskWarningBox } from "@oko-wallet-attached/components/modal_variants/common/risk_warning/risk_warning";
import { Avatar } from "@oko-wallet-attached/components/avatar/avatar";

interface EthereumSiweSignatureContentProps {
Expand All @@ -37,7 +37,7 @@ export const EthereumSiweSignatureContent: FC<
{isValidSiweMessage ? (
<SiweSigTitleBadge theme={theme} />
) : (
<SiweRiskWarningBox />
<RiskWarningBox />
)}

<div className={styles.metadataContainer}>
Expand All @@ -58,7 +58,7 @@ export const EthereumSiweSignatureContent: FC<
</div>

<Spacing height={8} />
<SignerAddressOrEmailForSiwe
<SignerInfo
origin={payload.origin}
signer={payload.signer}
initialViewType="Login Info"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { SignableMessage } from "viem";
import { parseSiweMessage, type SiweMessage } from "viem/siwe";

const ALLOW_PROTOCOLS = ["https:"];
const BYPASS_HOSTS = ["localhost"];
import { verifySignInOrigin } from "@oko-wallet-attached/components/modal_variants/common/sign_in_message";

export function getSiweMessage(
message: SignableMessage,
Expand Down Expand Up @@ -33,32 +32,5 @@ export function verifySiweMessage(
message: SiweMessage,
origin: string,
): boolean {
try {
const {
origin: originByPayload,
protocol: protocolByPayload,
host: hostByPayload,
} = new URL(origin);
const { origin: originByTxUri, protocol: protocolByTxUri } = new URL(
message.uri,
);

if (originByPayload !== originByTxUri || hostByPayload !== message.domain) {
return false;
}

// If scheme is not HTTPS, return false (when hostname is not localhost)
if (
!BYPASS_HOSTS.includes(hostByPayload.split(":")[0]) &&
(!ALLOW_PROTOCOLS.includes(protocolByPayload) ||
!ALLOW_PROTOCOLS.includes(protocolByTxUri))
) {
return false;
}
} catch (error) {
console.error(error);
return false;
}

return true;
return verifySignInOrigin(message.domain, message.uri, origin);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FC } from "react";
import { useMemo, useState, type FC } from "react";
import type { MakeSolMessageSignData } from "@oko-wallet/oko-sdk-core";
import { XCloseIcon } from "@oko-wallet/oko-common-ui/icons/x_close";
import { Spacing } from "@oko-wallet/oko-common-ui/spacing";
Expand All @@ -10,6 +10,13 @@ import { DemoView } from "@oko-wallet-attached/components/modal_variants/common/
import { SignWithOkoBox } from "@oko-wallet-attached/components/sign_with_oko_box/sign_with_oko_box";
import { useMessageSigModal } from "./use_message_sig_modal";
import { SolanaMessageSignatureContent } from "./sol_message_signature_content";
import {
getSiwsMessage,
verifySiwsMessage,
} from "@oko-wallet-attached/components/modal_variants/sol/siws_message";
import { SolanaSiwsSignatureContent } from "@oko-wallet-attached/components/modal_variants/sol/message_sig/siws_sig/make_siws_signature_content";
import { RiskWarningCheckBox } from "@oko-wallet-attached/components/modal_variants/common/risk_warning/risk_warning";
import { hexToUint8Array } from "@oko-wallet-attached/crypto/keygen_ed25519";

export interface MakeMessageSigModalProps {
getIsAborted: () => boolean;
Expand All @@ -22,12 +29,48 @@ export const MakeMessageSigModal: FC<MakeMessageSigModalProps> = ({
data,
modalId,
}) => {
const { onReject, onApprove, isLoading, isApproveEnabled, isDemo, theme } =
useMessageSigModal({
getIsAborted,
data,
modalId,
});
// Decode hex message to check for SIWS
const decodedMessage = useMemo(() => {
try {
const bytes = hexToUint8Array(data.payload.data.message);
return new TextDecoder().decode(bytes);
} catch {
return data.payload.data.message;
}
}, [data.payload.data.message]);

const siwsMessage = getSiwsMessage(decodedMessage);
const isValidSiwsMessage = siwsMessage
? verifySiwsMessage(siwsMessage, data.payload.origin)
: false;
const [isSiwsRiskWarningChecked, setIsSiwsRiskWarningChecked] =
useState(false);

const {
onReject,
onApprove,
isLoading,
isApproveEnabled: isApproveEnabledOriginal,
isDemo,
theme,
} = useMessageSigModal({
getIsAborted,
data,
modalId,
});

const isApproveEnabled = useMemo(() => {
if (siwsMessage && !isValidSiwsMessage) {
return isApproveEnabledOriginal && isSiwsRiskWarningChecked;
}

return isApproveEnabledOriginal;
}, [
isApproveEnabledOriginal,
isSiwsRiskWarningChecked,
siwsMessage,
isValidSiwsMessage,
]);

return (
<div className={styles.container}>
Expand All @@ -37,11 +80,25 @@ export const MakeMessageSigModal: FC<MakeMessageSigModalProps> = ({
</div>

<div className={styles.modalInnerContentContainer}>
<SolanaMessageSignatureContent payload={data.payload} />
{!!siwsMessage ? (
<SolanaSiwsSignatureContent payload={data.payload} theme={theme} />
) : (
<SolanaMessageSignatureContent payload={data.payload} />
)}
</div>

<Spacing height={20} />

{siwsMessage && !isValidSiwsMessage && (
<>
<RiskWarningCheckBox
checked={isSiwsRiskWarningChecked}
onChange={setIsSiwsRiskWarningChecked}
/>
<Spacing height={12} />
</>
)}

<div className={styles.buttonContainer}>
<Button
variant="secondary"
Expand Down
Loading