twitter auth flow

This commit is contained in:
Joel Gustafson
2021-11-19 15:35:42 -05:00
parent b354d81d67
commit d8e1135970
5 changed files with 31 additions and 11 deletions

View File

@@ -2,6 +2,7 @@ import * as t from "io-ts"
import { makeHandler, ServerError } from "next-rest/server"
import { prisma } from "utils/prisma"
import { getTextFromPublicKey, zkChatTwitterHandle } from "utils/verification"
const postRequestHeaders = t.type({
"content-type": t.literal("application/json"),
@@ -9,7 +10,6 @@ const postRequestHeaders = t.type({
const postRequestBody = t.type({
publicKey: t.string,
twitterHandle: t.string,
})
type PostRequestHeaders = t.TypeOf<typeof postRequestHeaders>
@@ -40,6 +40,11 @@ const twitterApiResponse = t.type({
oldest_id: t.string,
result_count: t.number,
}),
includes: t.type({
users: t.array(
t.type({ id: t.string, name: t.string, username: t.string })
),
}),
data: t.array(
t.type({
id: t.string,
@@ -52,11 +57,11 @@ export default makeHandler("/api/users", {
POST: {
headers: postRequestHeaders.is,
body: postRequestBody.is,
exec: async ({ body: { publicKey, twitterHandle } }) => {
const query = encodeURIComponent(`from:${twitterHandle} "${publicKey}"`)
exec: async ({ body: { publicKey } }) => {
const query = encodeURIComponent(`@${zkChatTwitterHandle} "${publicKey}"`)
const res = await fetch(
`https://api.twitter.com/2/tweets/search/recent?query=${query}`,
`https://api.twitter.com/2/tweets/search/recent?query=${query}&expansions=author_id&user.fields=username`,
{
headers: {
Authorization: `Bearer ${process.env.TWITTER_BEARER_TOKEN}`,
@@ -79,13 +84,19 @@ export default makeHandler("/api/users", {
const [{ id, text }] = data.data
// Change this if we wrap the public key with some text or anything
if (text !== publicKey) {
if (text !== getTextFromPublicKey(publicKey)) {
throw new ServerError(500, "Invalid tweet syntax")
}
const { username } = data.includes.users.find((user) => user.id === id)!
await prisma.user.create({
data: { publicKey, twitterHandle, verificationTweetId: id },
data: {
publicKey,
twitterId: id,
twitterHandle: username,
verificationTweetId: id,
},
})
return { headers: {}, body: undefined }

View File

@@ -35,7 +35,10 @@ export default function BackupPage(props: {}) {
<div className="max-w-lg m-auto font-mono">
<Header />
<div className="border border-gray-300 rounded-xl p-6">
<div>This is your ZK CHAT login token. Keep it secret and save it somewhere safe:</div>
<div>
This is your ZK CHAT login token. Keep it secret and save it somewhere
safe:
</div>
<textarea
className="block w-full outline-none py-5 px-6 my-6 rounded-xl border focus:border-blue-300 resize-none text-gray-800"
rows={3}

View File

@@ -32,8 +32,8 @@ export default function LoginPage(props: {}) {
<div className="border border-gray-300 rounded-xl p-6">
<div className="text-left mb-4">Log in with a secret token:</div>
<textarea
className="w-full resize-none px-4 py-3 rounded-xl outline-none border focus:border-blue-300 outline-none"
rows="3"
className="w-full resize-none px-4 py-3 rounded-xl outline-none border border-transparent"
rows={3}
placeholder="Your secret token"
value={value}
onChange={(event) => setValue(event.target.value)}

View File

@@ -12,6 +12,7 @@ datasource db {
model User {
publicKey String @id
twitterId String @unique
twitterHandle String @unique
verificationTweetId String @unique
messages Message[]
@@ -20,6 +21,6 @@ model User {
model Message {
id String @id @default(uuid())
authors User[]
body String
content String
proof Bytes
}

5
utils/verification.ts Normal file
View File

@@ -0,0 +1,5 @@
export const zkChatTwitterHandle = "zk_chat"
export function getTextFromPublicKey(publicKey: string) {
return `@zk_chat ${publicKey}`
}