Skip to content

Commit

Permalink
chore: generating the lightning address
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas Burtey committed Sep 21, 2023
1 parent 59bda84 commit 1eb8980
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 32 deletions.
2 changes: 2 additions & 0 deletions apps/boltcard/TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
- open telemetry

- add lnurl / lightning address / invoice
- generate token from the app
- type from db
92 changes: 64 additions & 28 deletions apps/boltcard/app/api/ln/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,50 @@ import {
GetUsdWalletIdQuery,
OnChainAddressCurrentDocument,
OnChainAddressCurrentMutation,
UserUpdateUsernameDocument,
UserUpdateUsernameMutation,
} from "@/services/core/generated"

gql`
query getUsdWalletId {
me {
defaultAccount {
id
defaultWalletId
wallets {
id
walletCurrency
balance
}
}
}
}
mutation onChainAddressCurrent($input: OnChainAddressCurrentInput!) {
onChainAddressCurrent(input: $input) {
errors {
message
}
address
}
}
mutation userUpdateUsername($input: UserUpdateUsernameInput!) {
userUpdateUsername(input: $input) {
errors {
message
__typename
}
user {
id
username
__typename
}
__typename
}
}
`

function generateReadableCode(numDigits: number, separator: number = 4): string {
const allowedNumbers = ["3", "4", "6", "7", "9"]
const allowedLetters = [
Expand Down Expand Up @@ -51,7 +93,7 @@ function generateReadableCode(numDigits: number, separator: number = 4): string
let code = ""
for (let i = 0; i < numDigits; i++) {
if (i > 0 && i % separator === 0) {
code += "-"
code += "_"
}
const randomIndex = Math.floor(Math.random() * allowedChars.length)
code += allowedChars[randomIndex]
Expand Down Expand Up @@ -159,15 +201,34 @@ const setupCard = async ({
})
const onchainAddress = dataOnchain.data?.onChainAddressCurrent?.address
if (!onchainAddress) {
console.log(dataOnchain.data?.onChainAddressCurrent, "dataOnchain")
console.dir(dataOnchain, "dataOnchain")
return NextResponse.json(
{ status: "ERROR", reason: `onchain address not found` },
{ status: 400 },
)
}

const id = generateReadableCode(12)
console.log({ id, onchainAddress }, "new card id")
const username = `card_${id}`

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
console.log({ id, username }, "new card id")

const dataUsername = await client.mutate<UserUpdateUsernameMutation>({
mutation: UserUpdateUsernameDocument,
variables: { input: { username } },
})

// FIXME userUpdateUsername.user?.username is buggy
// const usernameResult = dataUsername.data?.userUpdateUsername.user?.username
const usernameError = dataUsername.data?.userUpdateUsername.errors.length !== 0
if (usernameError) {
console.dir(dataUsername, { depth: null })
return NextResponse.json(
{ status: "ERROR", reason: `set username issue` },
{ status: 400 },
)
}

console.log({ id, onchainAddress, username, uid }, "new card id")

await markCardInitAsUsed(k2CmacKey)

Expand All @@ -188,31 +249,6 @@ const setupCard = async ({
return card
}

gql`
query getUsdWalletId {
me {
defaultAccount {
id
defaultWalletId
wallets {
id
walletCurrency
balance
}
}
}
}
mutation onChainAddressCurrent($input: OnChainAddressCurrentInput!) {
onChainAddressCurrent(input: $input) {
errors {
message
}
address
}
}
`

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const raw_p = searchParams.get("p")
Expand Down
3 changes: 3 additions & 0 deletions apps/boltcard/app/card/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export default async function Home({ params }: { params: { id: string } }) {
<li>
<strong>Onchain Address:</strong> {cardInfo.onchainAddress}
</li>
<li>
<strong>Lightning address</strong> {cardInfo.lightningAddress}
</li>
<li>
<strong>Enabled:</strong> {cardInfo.enabled ? "Yes" : "No"}
</li>
Expand Down
8 changes: 6 additions & 2 deletions apps/boltcard/bats/e2e-test.bats
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
load "../../../test/bats/helpers/setup-and-teardown"
load "../../../test/bats/helpers/ln"

random_phone() {
printf "+1%010d\n" $(( ($RANDOM * 1000000) + ($RANDOM % 1000000) ))
}

@test "auth: create user" {
login_user "alice" "+16505554321" "000000"
login_user "alice" "$(random_phone)" "000000"
}

@test "auth: create card" {
Expand Down Expand Up @@ -59,7 +63,7 @@ load "../../../test/bats/helpers/ln"
bitcoin_cli -generate 2

# retry 30 1 check_for_onchain_initiated_settled "$token_name" "$address"
sleep 2
sleep 5
}

@test "callback" {
Expand Down
2 changes: 2 additions & 0 deletions apps/boltcard/services/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export const AES_DECRYPT_KEY =
process.env.AES_DECRYPT_KEY ?? "0c3b25d92b38ae443229dd59ad34b85d"

export const aesDecryptKey = Buffer.from(AES_DECRYPT_KEY, "hex")

export const lightningDomain = process.env.LIGHTNING_DOMAIN ?? "localhost"
51 changes: 50 additions & 1 deletion apps/boltcard/services/core/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,13 @@ export type OnChainAddressCurrentMutationVariables = Exact<{

export type OnChainAddressCurrentMutation = { readonly __typename: 'Mutation', readonly onChainAddressCurrent: { readonly __typename: 'OnChainAddressPayload', readonly address?: string | null, readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly message: string }> } };

export type UserUpdateUsernameMutationVariables = Exact<{
input: UserUpdateUsernameInput;
}>;


export type UserUpdateUsernameMutation = { readonly __typename: 'Mutation', readonly userUpdateUsername: { readonly __typename: 'UserUpdateUsernamePayload', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly message: string }>, readonly user?: { readonly __typename: 'User', readonly id: string, readonly username?: string | null } | null } };

export const TransactionListFragmentDoc = gql`
fragment TransactionList on TransactionConnection {
pageInfo {
Expand Down Expand Up @@ -2215,4 +2222,46 @@ export function useOnChainAddressCurrentMutation(baseOptions?: Apollo.MutationHo
}
export type OnChainAddressCurrentMutationHookResult = ReturnType<typeof useOnChainAddressCurrentMutation>;
export type OnChainAddressCurrentMutationResult = Apollo.MutationResult<OnChainAddressCurrentMutation>;
export type OnChainAddressCurrentMutationOptions = Apollo.BaseMutationOptions<OnChainAddressCurrentMutation, OnChainAddressCurrentMutationVariables>;
export type OnChainAddressCurrentMutationOptions = Apollo.BaseMutationOptions<OnChainAddressCurrentMutation, OnChainAddressCurrentMutationVariables>;
export const UserUpdateUsernameDocument = gql`
mutation userUpdateUsername($input: UserUpdateUsernameInput!) {
userUpdateUsername(input: $input) {
errors {
message
__typename
}
user {
id
username
__typename
}
__typename
}
}
`;
export type UserUpdateUsernameMutationFn = Apollo.MutationFunction<UserUpdateUsernameMutation, UserUpdateUsernameMutationVariables>;

/**
* __useUserUpdateUsernameMutation__
*
* To run a mutation, you first call `useUserUpdateUsernameMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUserUpdateUsernameMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [userUpdateUsernameMutation, { data, loading, error }] = useUserUpdateUsernameMutation({
* variables: {
* input: // value for 'input'
* },
* });
*/
export function useUserUpdateUsernameMutation(baseOptions?: Apollo.MutationHookOptions<UserUpdateUsernameMutation, UserUpdateUsernameMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UserUpdateUsernameMutation, UserUpdateUsernameMutationVariables>(UserUpdateUsernameDocument, options);
}
export type UserUpdateUsernameMutationHookResult = ReturnType<typeof useUserUpdateUsernameMutation>;
export type UserUpdateUsernameMutationResult = Apollo.MutationResult<UserUpdateUsernameMutation>;
export type UserUpdateUsernameMutationOptions = Apollo.BaseMutationOptions<UserUpdateUsernameMutation, UserUpdateUsernameMutationVariables>;
9 changes: 8 additions & 1 deletion apps/boltcard/services/db/card.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { lightningDomain } from "../config"

import { knex } from "./connection"

export async function fetchByUid(uid: string) {
Expand All @@ -23,7 +25,12 @@ export async function fetchPublicByCardId(cardId: string) {
.where("id", cardId)
.select("id", "uid", "onchainAddress", "enabled")
.first()
return result

// TODO: refactor with a card service !== db
const username = `card_${result.id}`
const lightningAddress = `${username}@${lightningDomain}`

return { ...result, username, lightningAddress }
}

interface CardInput {
Expand Down

0 comments on commit 1eb8980

Please sign in to comment.