add forgetten lnurl-auth files
This commit is contained in:
parent
2e26e421e7
commit
9a15c228dc
|
@ -0,0 +1,26 @@
|
|||
import { randomBytes } from 'crypto'
|
||||
import { bech32 } from 'bech32'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
lnAuth: async (parent, { k1 }, { models }) => {
|
||||
return await models.lnAuth.findUnique({ where: { k1 } })
|
||||
}
|
||||
},
|
||||
Mutation: {
|
||||
createAuth: async (parent, args, { models }) => {
|
||||
const k1 = randomBytes(32).toString('hex')
|
||||
return await models.lnAuth.create({ data: { k1 } })
|
||||
}
|
||||
},
|
||||
LnAuth: {
|
||||
encodedUrl: async (lnAuth, args, { models }) => {
|
||||
const url = new URL(process.env.LNAUTH_URL)
|
||||
url.searchParams.set('tag', 'login')
|
||||
url.searchParams.set('k1', lnAuth.k1)
|
||||
// bech32 encode url
|
||||
const words = bech32.toWords(Buffer.from(url.toString(), 'utf8'))
|
||||
return bech32.encode('lnurl', words, 1023)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { gql } from 'apollo-server-micro'
|
||||
|
||||
export default gql`
|
||||
extend type Query {
|
||||
lnAuth(k1: String!): LnAuth!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAuth: LnAuth!
|
||||
}
|
||||
|
||||
type LnAuth {
|
||||
id: ID!
|
||||
createdAt: String!
|
||||
k1: String!
|
||||
pubkey: String
|
||||
encodedUrl: String!
|
||||
}
|
||||
`
|
|
@ -0,0 +1,31 @@
|
|||
import QRCode from 'qrcode.react'
|
||||
import { CopyInput, InputSkeleton } from './form'
|
||||
import InvoiceStatus from './invoice-status'
|
||||
|
||||
export default function LnQR ({ value, statusVariant, status }) {
|
||||
const qrValue = 'lightning:' + value.toUpperCase()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<QRCode className='h-auto mw-100' value={qrValue} renderAs='svg' size={300} />
|
||||
</div>
|
||||
<div className='mt-3 w-100'>
|
||||
<CopyInput type='text' placeholder={value} readOnly />
|
||||
</div>
|
||||
<InvoiceStatus variant={statusVariant} status={status} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function LnQRSkeleton ({ status }) {
|
||||
return (
|
||||
<>
|
||||
<div className='h-auto w-100 clouds' style={{ paddingTop: 'min(300px, 100%)', maxWidth: '300px' }} />
|
||||
<div className='mt-3 w-100'>
|
||||
<InputSkeleton />
|
||||
</div>
|
||||
<InvoiceStatus variant='default' status={status} />
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { randomBytes } from 'crypto'
|
||||
import { bech32 } from 'bech32'
|
||||
|
||||
export function lnurlAuth (params) {
|
||||
// generate secret (32 random bytes)
|
||||
const secret = Buffer.from(randomBytes(32), 'hex')
|
||||
// create url
|
||||
const url = new URL(process.env.LNAUTH_URL)
|
||||
url.searchParams = new URLSearchParams({
|
||||
...params,
|
||||
k1: secret
|
||||
})
|
||||
// bech32 encode url
|
||||
const words = bech32.toWords(Buffer.from(url.toString(), 'utf8'))
|
||||
const encodedUrl = bech32.encode('lnurl', words, 1023)
|
||||
return { secret, encodedUrl }
|
||||
}
|
|
@ -94,7 +94,7 @@ const options = {
|
|||
})
|
||||
],
|
||||
adapter: Adapters.Prisma.Adapter({ prisma }),
|
||||
secret: process.env.SECRET,
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
session: { jwt: true },
|
||||
jwt: {
|
||||
signingKey: process.env.JWT_SIGNING_PRIVATE_KEY
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// verify it's signed
|
||||
// store pubkey in db
|
||||
// create user with pubkey and name truncated pubkey
|
||||
import secp256k1 from 'secp256k1'
|
||||
import models from '../../api/models'
|
||||
|
||||
export default async ({ query }, res) => {
|
||||
const sig = Buffer.from(query.sig, 'hex')
|
||||
const k1 = Buffer.from(query.k1, 'hex')
|
||||
const key = Buffer.from(query.key, 'hex')
|
||||
const signature = secp256k1.signatureImport(sig)
|
||||
try {
|
||||
if (secp256k1.ecdsaVerify(signature, k1, key)) {
|
||||
await models.lnAuth.update({ where: { k1: query.k1 }, data: { pubkey: query.key } })
|
||||
return res.status(200).json({ status: 'OK' })
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
return res.status(400).json({ status: 'ERROR', reason: 'signature verification failed' })
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[pubkey]` on the table `users` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" ADD COLUMN "pubkey" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LnAuth" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"k1" TEXT NOT NULL,
|
||||
"pubkey" TEXT,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LnAuth.k1_unique" ON "LnAuth"("k1");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users.pubkey_unique" ON "users"("pubkey");
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 10.1907L8.48754 21L12.6726 12.7423H5L14.6157 3L11.5267 10.2835L19 10.1907Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 207 B |
Loading…
Reference in New Issue