-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathverify-signature.ts
134 lines (115 loc) · 3.54 KB
/
verify-signature.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import {
Header,
Payload,
Signature,
SIWWeb3,
} from "@web3auth/sign-in-with-web3";
import bs58 from "bs58";
import type { NextApiRequest, NextApiResponse } from "next";
// These can be supplied by the server
const domain = "localhost";
const origin = "https://localhost:3000/api/verify-signature";
const createWeb3Message = (
statement: string,
nonce: string | undefined = undefined,
issuedAt: string | undefined = undefined,
address: string = "<address>"
) => {
const header = new Header();
header.t = "sip99";
const payload = new Payload();
payload.domain = domain;
// This needs to be supplied by the client
payload.address = address;
payload.uri = origin;
payload.statement = statement;
payload.version = "1";
payload.chainId = 1;
if (nonce && issuedAt) {
payload.nonce = nonce;
payload.issuedAt = issuedAt;
}
const message = new SIWWeb3({
header,
payload,
network: "solana",
});
return message;
};
// Utilizes the Solana Pay / auth proposal: https://twitter.com/jordaaash/status/1560386497370419200
// With Solana Pay transaction requests, there isn't (technically) a frontend to construct a well-formed message, so we'll handle it ourselves
// Extends with a message to sign
const get = (req: NextApiRequest, res: NextApiResponse) => {
const label = "Exiled Apes Academy";
const icon =
"https://exiledapes.academy/wp-content/uploads/2021/09/X_share.png";
const message = createWeb3Message(
`Sign this message to validate ownership of this wallet`
);
res.status(200).send({
label,
icon,
message: message.prepareMessage(),
nonce: message.payload.nonce,
issuedAt: message.payload.issuedAt,
});
};
const verifyMessage = async ({
message,
signature,
}: {
message: SIWWeb3;
signature: Signature;
}) => {
return await message.verify(message.payload, signature, message.network);
};
type PostData = {
message: string;
account: string;
};
// Utilizes the Solana Pay / auth proposal: https://twitter.com/jordaaash/status/1560386497370419200
const post = async (req: NextApiRequest, res: NextApiResponse<PostData>) => {
const { body } = req;
try {
const { account, message, nonce, issuedAt, signature } = JSON.parse(body);
console.info({ account, message, nonce, issuedAt, signature });
const messageToVerify = createWeb3Message(
`Sign this message to validate ownership of this wallet`,
nonce,
issuedAt,
account
);
const signatureToVerify = new Signature();
signatureToVerify.s = signature;
signatureToVerify.t = "sip99";
// The nonce value should likely be generated / persisted server-side, or perhaps encoded with a server-side keypair
// For the purposes of this example we'll assume its a valid nonce that we generated
const isVerified = await verifyMessage({
message: messageToVerify,
signature: signatureToVerify,
});
if (isVerified.success) {
/*
* This is where you can do some custom logic to persist the connection between the user account and this account
* or issue a cookie or some other strategy for persisting the authentication here
*/
return res.status(200).end();
} else {
return res.status(401).end();
}
} catch (e) {
console.error(e);
}
res.status(500).end();
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<PostData>
) {
if (req.method === "POST") {
return await post(req, res);
} else if (req.method === "GET") {
return await get(req, res);
}
res.status(405).end();
}