spruceid / siwe-py

A Python implementation of Sign-In with Ethereum
https://login.xyz
Apache License 2.0
67 stars 30 forks source link

JS and Python SIWE message compatibility #35

Closed poundbang closed 1 year ago

poundbang commented 1 year ago

Hello,

I am using the frontend code from quick start for SIWE to a Python backend. I am running into a ValueError when parsing on Python side.

Frontend:

async function createSiweMessage(address, statement) {
    const res = await fetch(`${BACKEND_ADDR}/nonce`, {
        credentials: 'include',
    });
    const message = new SiweMessage({
        domain,
        address,
        statement,
        uri: origin,
        version: '1',
        chainId: '1',
        nonce: await res.text()
    });
    console.log(message.prepareMessage());
    return message.prepareMessage();
}

Backend

@app.post("/verify")
async def verify(request: Request, response: Response): 
    siwe_message: SiweMessage = None
    data = await request.json()
    print(f"Data: {data}")
    if  not "message" in data or not "signature" in data:
        response.status_code = 422
        return { "message": 'Expected prepareMessage object as body.' }

    try:
        print(f"Data message: {data['message']}")
        siwe_message: SiweMessage = SiweMessage(message=data["message"])
        print(f"SiweMessage: {siwe_message}")
    except ValueError as ve:
        print(f"Parsing Failed {ve}")

message:

Data: {'message': 'localhost:8080 wants you to sign in with your Ethereum account:\n0xDb26......A14B\n\nSign in with Ethereum to the app.\n\nURI: http://localhost:8080\nVersion: 1\nChain ID: 1\nNonce: "WPxoHcfeqjQ"\nIssued At: 2023-03-09T22:47:49.095Z', 'signature': '0xb0b3cf5737017aa2aaf0b352cfe6454cb6565c016ecfca90068358db95d3e854090af77e93fe9f2e6938948b21ca595d638990e5805334360b0bf70629bb19a61c'}

I noticed that:

siwe/lib/clint.ts joins the statment with a newline:

toMessage(): string {
        const header = `${this.domain} wants you to sign in with your Ethereum account:`;
        const uriField = `URI: ${this.uri}`;
        let prefix = [header, this.address].join('\n');
        const versionField = `Version: ${this.version}`;

Could this possibly be due to this field in https://github.com/spruceid/siwe-py/blob/ba79385b2c7a51cf61a5d3cb7a7ca93d7c57ac5d/siwe/siwe.py#L131

    statement: Optional[str] = Field(
        None, regex="^[^\n]+$"
    )  # Human-readable ASCII assertion that the user will sign, and it must not contain `\n`.

thanks.

poundbang commented 1 year ago

I figured it out: the Nonce was in " quotes.

chairz commented 1 year ago

Hi @poundbang, i am facing the same issue as you. How did you solve the double quotes issue?