mirror of
https://github.com/apotdevin/thunderhub.git
synced 2024-11-19 09:50:03 +01:00
chore: 🔧 add ln-auth (#148)
This commit is contained in:
parent
78efc34e68
commit
56b690753b
27
package-lock.json
generated
27
package-lock.json
generated
@ -7309,6 +7309,15 @@
|
|||||||
"@types/redis": "*"
|
"@types/redis": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/secp256k1": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/serve-static": {
|
"@types/serve-static": {
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz",
|
||||||
@ -9612,6 +9621,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bip39": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "11.11.6",
|
||||||
|
"create-hash": "^1.1.0",
|
||||||
|
"pbkdf2": "^3.0.9",
|
||||||
|
"randombytes": "^2.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "11.11.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
|
||||||
|
"integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bip65": {
|
"bip65": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz",
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
"balanceofsatoshis": "^5.47.0",
|
"balanceofsatoshis": "^5.47.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bech32": "^1.1.4",
|
"bech32": "^1.1.4",
|
||||||
|
"bip32": "^2.0.5",
|
||||||
|
"bip39": "^3.0.2",
|
||||||
"cookie": "^0.4.1",
|
"cookie": "^0.4.1",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
@ -72,6 +74,7 @@
|
|||||||
"react-table": "^7.5.1",
|
"react-table": "^7.5.1",
|
||||||
"react-toastify": "^6.0.8",
|
"react-toastify": "^6.0.8",
|
||||||
"react-tooltip": "^4.2.10",
|
"react-tooltip": "^4.2.10",
|
||||||
|
"secp256k1": "^4.0.2",
|
||||||
"styled-components": "^5.2.0",
|
"styled-components": "^5.2.0",
|
||||||
"styled-react-modal": "^2.0.1",
|
"styled-react-modal": "^2.0.1",
|
||||||
"styled-theming": "^2.2.0",
|
"styled-theming": "^2.2.0",
|
||||||
@ -112,6 +115,7 @@
|
|||||||
"@types/qrcode.react": "^1.0.1",
|
"@types/qrcode.react": "^1.0.1",
|
||||||
"@types/react-copy-to-clipboard": "^4.3.0",
|
"@types/react-copy-to-clipboard": "^4.3.0",
|
||||||
"@types/react-table": "^7.0.23",
|
"@types/react-table": "^7.0.23",
|
||||||
|
"@types/secp256k1": "^4.0.1",
|
||||||
"@types/styled-components": "^5.1.3",
|
"@types/styled-components": "^5.1.3",
|
||||||
"@types/styled-react-modal": "^1.2.0",
|
"@types/styled-react-modal": "^1.2.0",
|
||||||
"@types/styled-theming": "^2.2.5",
|
"@types/styled-theming": "^2.2.5",
|
||||||
|
@ -3,14 +3,27 @@ import { to } from 'server/helpers/async';
|
|||||||
import { logger } from 'server/helpers/logger';
|
import { logger } from 'server/helpers/logger';
|
||||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||||
import { ContextType } from 'server/types/apiTypes';
|
import { ContextType } from 'server/types/apiTypes';
|
||||||
import { createInvoice, decodePaymentRequest, pay } from 'ln-service';
|
import {
|
||||||
|
createInvoice,
|
||||||
|
decodePaymentRequest,
|
||||||
|
pay,
|
||||||
|
getWalletInfo,
|
||||||
|
diffieHellmanComputeSecret,
|
||||||
|
} from 'ln-service';
|
||||||
import {
|
import {
|
||||||
CreateInvoiceType,
|
CreateInvoiceType,
|
||||||
DecodedType,
|
DecodedType,
|
||||||
|
DiffieHellmanComputeSecretType,
|
||||||
|
GetWalletInfoType,
|
||||||
PayInvoiceType,
|
PayInvoiceType,
|
||||||
} from 'server/types/ln-service.types';
|
} from 'server/types/ln-service.types';
|
||||||
// import { GetPublicKeyType } from 'server/types/ln-service.types';
|
|
||||||
// import hmacSHA256 from 'crypto-js/hmac-sha256';
|
import hmacSHA256 from 'crypto-js/hmac-sha256';
|
||||||
|
import { enc } from 'crypto-js';
|
||||||
|
import * as bip39 from 'bip39';
|
||||||
|
import * as bip32 from 'bip32';
|
||||||
|
import * as secp256k1 from 'secp256k1';
|
||||||
|
import { BIP32Interface } from 'bip32';
|
||||||
|
|
||||||
type LnUrlPayResponseType = {
|
type LnUrlPayResponseType = {
|
||||||
pr?: string;
|
pr?: string;
|
||||||
@ -57,34 +70,99 @@ type WithdrawRequestType = {
|
|||||||
type RequestType = PayRequestType | WithdrawRequestType;
|
type RequestType = PayRequestType | WithdrawRequestType;
|
||||||
type RequestWithType = { isTypeOf: string } & RequestType;
|
type RequestWithType = { isTypeOf: string } & RequestType;
|
||||||
|
|
||||||
|
const fromHexString = (hexString: string) =>
|
||||||
|
new Uint8Array(
|
||||||
|
hexString.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
|
||||||
|
);
|
||||||
|
|
||||||
|
const toHexString = (bytes: Uint8Array) =>
|
||||||
|
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
|
||||||
|
|
||||||
export const lnUrlResolvers = {
|
export const lnUrlResolvers = {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
lnUrl: async (
|
lnUrlAuth: async (
|
||||||
_: undefined,
|
_: undefined,
|
||||||
{ type, url }: LnUrlParams,
|
{ url }: LnUrlParams,
|
||||||
context: ContextType
|
context: ContextType
|
||||||
): Promise<string> => {
|
): Promise<{ status: string; message: string }> => {
|
||||||
await requestLimiter(context.ip, 'lnUrl');
|
await requestLimiter(context.ip, 'lnUrl');
|
||||||
|
const { lnd } = context;
|
||||||
|
|
||||||
// const fullUrl = new URL(url);
|
const domainUrl = new URL(url);
|
||||||
|
const host = domainUrl.host;
|
||||||
|
|
||||||
// const { lnd } = context;
|
const k1 = domainUrl.searchParams.get('k1');
|
||||||
|
|
||||||
// if (type === 'login') {
|
if (!host || !k1) {
|
||||||
// logger.debug({ type, url });
|
logger.error('Missing host or k1 in url: %o', url);
|
||||||
|
throw new Error('WrongUrlFormat');
|
||||||
|
}
|
||||||
|
|
||||||
// const info = await to<GetPublicKeyType>(
|
const wallet = await to<GetWalletInfoType>(getWalletInfo({ lnd }));
|
||||||
// getPublicKey({ lnd, family: 138, index: 0 })
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const hashed = hmacSHA256(fullUrl.host, info.public_key);
|
// Generate entropy
|
||||||
|
const secret = await to<DiffieHellmanComputeSecretType>(
|
||||||
|
diffieHellmanComputeSecret({
|
||||||
|
lnd,
|
||||||
|
key_family: 138,
|
||||||
|
key_index: 0,
|
||||||
|
partner_public_key: wallet?.public_key,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// return info.public_key;
|
// Generate hash from host and entropy
|
||||||
// }
|
const hashed = hmacSHA256(host, secret.secret).toString(enc.Hex);
|
||||||
|
|
||||||
logger.debug({ type, url });
|
const indexes =
|
||||||
|
hashed.match(/.{1,4}/g)?.map(index => parseInt(index, 16)) || [];
|
||||||
|
|
||||||
return 'confirmed';
|
// Generate private seed from entropy
|
||||||
|
const secretKey = bip39.entropyToMnemonic(hashed);
|
||||||
|
const base58 = bip39.mnemonicToSeedSync(secretKey);
|
||||||
|
|
||||||
|
// Derive private seed from previous private seed and path
|
||||||
|
const node: BIP32Interface = bip32.fromSeed(base58);
|
||||||
|
const derived = node.derivePath(
|
||||||
|
`m/138/${indexes[0]}/${indexes[1]}/${indexes[2]}/${indexes[3]}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get private and public key from derived private seed
|
||||||
|
const privateKey = derived.privateKey?.toString('hex');
|
||||||
|
const linkingKey = derived.publicKey.toString('hex');
|
||||||
|
|
||||||
|
if (!privateKey || !linkingKey) {
|
||||||
|
logger.error('Error deriving private or public key: %o', url);
|
||||||
|
throw new Error('ErrorDerivingPrivateKey');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign k1 with derived private seed
|
||||||
|
const sigObj = secp256k1.ecdsaSign(
|
||||||
|
fromHexString(k1),
|
||||||
|
fromHexString(privateKey)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get signature
|
||||||
|
const signature = secp256k1.signatureExport(sigObj.signature);
|
||||||
|
const encodedSignature = toHexString(signature);
|
||||||
|
|
||||||
|
// Build final url with signature and public key
|
||||||
|
const finalUrl = `${url}&sig=${encodedSignature}&key=${linkingKey}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(finalUrl);
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
|
logger.debug('LnUrlAuth response: %o', json);
|
||||||
|
|
||||||
|
if (json.status === 'ERROR') {
|
||||||
|
return { ...json, message: json.reason || 'LnServiceError' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...json, message: json.event || 'LnServiceSuccess' };
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error authenticating with LnUrl service: %o', error);
|
||||||
|
throw new Error('ProblemAuthenticatingWithLnUrlService');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fetchLnUrl: async (
|
fetchLnUrl: async (
|
||||||
_: undefined,
|
_: undefined,
|
||||||
|
@ -21,6 +21,11 @@ export const lnUrlTypes = gql`
|
|||||||
|
|
||||||
union LnUrlRequest = WithdrawRequest | PayRequest
|
union LnUrlRequest = WithdrawRequest | PayRequest
|
||||||
|
|
||||||
|
type AuthResponse {
|
||||||
|
status: String!
|
||||||
|
message: String!
|
||||||
|
}
|
||||||
|
|
||||||
type PaySuccess {
|
type PaySuccess {
|
||||||
tag: String
|
tag: String
|
||||||
description: String
|
description: String
|
||||||
|
@ -91,6 +91,7 @@ export const queryTypes = gql`
|
|||||||
|
|
||||||
export const mutationTypes = gql`
|
export const mutationTypes = gql`
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
lnUrlAuth(url: String!): AuthResponse!
|
||||||
lnUrlPay(callback: String!, amount: Int!, comment: String): PaySuccess!
|
lnUrlPay(callback: String!, amount: Int!, comment: String): PaySuccess!
|
||||||
lnUrlWithdraw(
|
lnUrlWithdraw(
|
||||||
callback: String!
|
callback: String!
|
||||||
@ -99,7 +100,6 @@ export const mutationTypes = gql`
|
|||||||
description: String
|
description: String
|
||||||
): String!
|
): String!
|
||||||
fetchLnUrl(url: String!): LnUrlRequest
|
fetchLnUrl(url: String!): LnUrlRequest
|
||||||
lnUrl(type: String!, url: String!): String!
|
|
||||||
createBaseInvoice(amount: Int!): baseInvoiceType
|
createBaseInvoice(amount: Int!): baseInvoiceType
|
||||||
createThunderPoints(
|
createThunderPoints(
|
||||||
id: String!
|
id: String!
|
||||||
|
@ -103,6 +103,10 @@ export type GetWalletInfoType = {
|
|||||||
public_key: string;
|
public_key: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DiffieHellmanComputeSecretType = {
|
||||||
|
secret: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type GetNodeType = { alias: string; color: string };
|
export type GetNodeType = { alias: string; color: string };
|
||||||
|
|
||||||
export type UtxoType = {};
|
export type UtxoType = {};
|
||||||
|
@ -19,6 +19,19 @@ export type FetchLnUrlMutation = (
|
|||||||
)> }
|
)> }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type AuthLnUrlMutationVariables = Types.Exact<{
|
||||||
|
url: Types.Scalars['String'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type AuthLnUrlMutation = (
|
||||||
|
{ __typename?: 'Mutation' }
|
||||||
|
& { lnUrlAuth: (
|
||||||
|
{ __typename?: 'AuthResponse' }
|
||||||
|
& Pick<Types.AuthResponse, 'status' | 'message'>
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
export type PayLnUrlMutationVariables = Types.Exact<{
|
export type PayLnUrlMutationVariables = Types.Exact<{
|
||||||
callback: Types.Scalars['String'];
|
callback: Types.Scalars['String'];
|
||||||
amount: Types.Scalars['Int'];
|
amount: Types.Scalars['Int'];
|
||||||
@ -95,6 +108,39 @@ export function useFetchLnUrlMutation(baseOptions?: Apollo.MutationHookOptions<F
|
|||||||
export type FetchLnUrlMutationHookResult = ReturnType<typeof useFetchLnUrlMutation>;
|
export type FetchLnUrlMutationHookResult = ReturnType<typeof useFetchLnUrlMutation>;
|
||||||
export type FetchLnUrlMutationResult = Apollo.MutationResult<FetchLnUrlMutation>;
|
export type FetchLnUrlMutationResult = Apollo.MutationResult<FetchLnUrlMutation>;
|
||||||
export type FetchLnUrlMutationOptions = Apollo.BaseMutationOptions<FetchLnUrlMutation, FetchLnUrlMutationVariables>;
|
export type FetchLnUrlMutationOptions = Apollo.BaseMutationOptions<FetchLnUrlMutation, FetchLnUrlMutationVariables>;
|
||||||
|
export const AuthLnUrlDocument = gql`
|
||||||
|
mutation AuthLnUrl($url: String!) {
|
||||||
|
lnUrlAuth(url: $url) {
|
||||||
|
status
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type AuthLnUrlMutationFn = Apollo.MutationFunction<AuthLnUrlMutation, AuthLnUrlMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useAuthLnUrlMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useAuthLnUrlMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useAuthLnUrlMutation` 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 [authLnUrlMutation, { data, loading, error }] = useAuthLnUrlMutation({
|
||||||
|
* variables: {
|
||||||
|
* url: // value for 'url'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useAuthLnUrlMutation(baseOptions?: Apollo.MutationHookOptions<AuthLnUrlMutation, AuthLnUrlMutationVariables>) {
|
||||||
|
return Apollo.useMutation<AuthLnUrlMutation, AuthLnUrlMutationVariables>(AuthLnUrlDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type AuthLnUrlMutationHookResult = ReturnType<typeof useAuthLnUrlMutation>;
|
||||||
|
export type AuthLnUrlMutationResult = Apollo.MutationResult<AuthLnUrlMutation>;
|
||||||
|
export type AuthLnUrlMutationOptions = Apollo.BaseMutationOptions<AuthLnUrlMutation, AuthLnUrlMutationVariables>;
|
||||||
export const PayLnUrlDocument = gql`
|
export const PayLnUrlDocument = gql`
|
||||||
mutation PayLnUrl($callback: String!, $amount: Int!, $comment: String) {
|
mutation PayLnUrl($callback: String!, $amount: Int!, $comment: String) {
|
||||||
lnUrlPay(callback: $callback, amount: $amount, comment: $comment) {
|
lnUrlPay(callback: $callback, amount: $amount, comment: $comment) {
|
||||||
|
@ -23,6 +23,15 @@ export const FETCH_LN_URL = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const AUTH_LN_URL = gql`
|
||||||
|
mutation AuthLnUrl($url: String!) {
|
||||||
|
lnUrlAuth(url: $url) {
|
||||||
|
status
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const PAY_LN_URL = gql`
|
export const PAY_LN_URL = gql`
|
||||||
mutation PayLnUrl($callback: String!, $amount: Int!, $comment: String) {
|
mutation PayLnUrl($callback: String!, $amount: Int!, $comment: String) {
|
||||||
lnUrlPay(callback: $callback, amount: $amount, comment: $comment) {
|
lnUrlPay(callback: $callback, amount: $amount, comment: $comment) {
|
||||||
|
@ -208,10 +208,10 @@ export type QueryGetSessionTokenArgs = {
|
|||||||
|
|
||||||
export type Mutation = {
|
export type Mutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
|
lnUrlAuth: AuthResponse;
|
||||||
lnUrlPay: PaySuccess;
|
lnUrlPay: PaySuccess;
|
||||||
lnUrlWithdraw: Scalars['String'];
|
lnUrlWithdraw: Scalars['String'];
|
||||||
fetchLnUrl?: Maybe<LnUrlRequest>;
|
fetchLnUrl?: Maybe<LnUrlRequest>;
|
||||||
lnUrl: Scalars['String'];
|
|
||||||
createBaseInvoice?: Maybe<BaseInvoiceType>;
|
createBaseInvoice?: Maybe<BaseInvoiceType>;
|
||||||
createThunderPoints: Scalars['Boolean'];
|
createThunderPoints: Scalars['Boolean'];
|
||||||
closeChannel?: Maybe<CloseChannelType>;
|
closeChannel?: Maybe<CloseChannelType>;
|
||||||
@ -234,6 +234,11 @@ export type Mutation = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationLnUrlAuthArgs = {
|
||||||
|
url: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLnUrlPayArgs = {
|
export type MutationLnUrlPayArgs = {
|
||||||
callback: Scalars['String'];
|
callback: Scalars['String'];
|
||||||
amount: Scalars['Int'];
|
amount: Scalars['Int'];
|
||||||
@ -254,12 +259,6 @@ export type MutationFetchLnUrlArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLnUrlArgs = {
|
|
||||||
type: Scalars['String'];
|
|
||||||
url: Scalars['String'];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateBaseInvoiceArgs = {
|
export type MutationCreateBaseInvoiceArgs = {
|
||||||
amount: Scalars['Int'];
|
amount: Scalars['Int'];
|
||||||
};
|
};
|
||||||
@ -1041,6 +1040,12 @@ export type PayRequest = {
|
|||||||
|
|
||||||
export type LnUrlRequest = WithdrawRequest | PayRequest;
|
export type LnUrlRequest = WithdrawRequest | PayRequest;
|
||||||
|
|
||||||
|
export type AuthResponse = {
|
||||||
|
__typename?: 'AuthResponse';
|
||||||
|
status: Scalars['String'];
|
||||||
|
message: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
export type PaySuccess = {
|
export type PaySuccess = {
|
||||||
__typename?: 'PaySuccess';
|
__typename?: 'PaySuccess';
|
||||||
tag?: Maybe<Scalars['String']>;
|
tag?: Maybe<Scalars['String']>;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
||||||
import { Card } from 'src/components/generic/Styled';
|
import { Card } from 'src/components/generic/Styled';
|
||||||
import { InputWithDeco } from 'src/components/input/InputWithDeco';
|
import { InputWithDeco } from 'src/components/input/InputWithDeco';
|
||||||
import Modal from 'src/components/modal/ReactModal';
|
import Modal from 'src/components/modal/ReactModal';
|
||||||
|
import { useAuthLnUrlMutation } from 'src/graphql/mutations/__generated__/lnUrl.generated';
|
||||||
|
import { getErrorContent } from 'src/utils/error';
|
||||||
import { decodeLnUrl } from 'src/utils/url';
|
import { decodeLnUrl } from 'src/utils/url';
|
||||||
import { LnUrlModal } from './lnUrlModal';
|
import { LnUrlModal } from './lnUrlModal';
|
||||||
|
|
||||||
@ -13,6 +15,24 @@ export const LnUrlCard = () => {
|
|||||||
const [type, setType] = useState<string>('');
|
const [type, setType] = useState<string>('');
|
||||||
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [auth, { data, loading }] = useAuthLnUrlMutation({
|
||||||
|
onError: error => toast.error(getErrorContent(error)),
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading || !data?.lnUrlAuth) return;
|
||||||
|
|
||||||
|
const { status, message } = data.lnUrlAuth;
|
||||||
|
if (status === 'ERROR') {
|
||||||
|
toast.error(message);
|
||||||
|
} else {
|
||||||
|
toast.success(message);
|
||||||
|
setLnUrl('');
|
||||||
|
setUrl('');
|
||||||
|
setType('');
|
||||||
|
}
|
||||||
|
}, [data, loading]);
|
||||||
|
|
||||||
const handleDecode = () => {
|
const handleDecode = () => {
|
||||||
if (!lnurl) {
|
if (!lnurl) {
|
||||||
toast.warning('Please input a LNURL');
|
toast.warning('Please input a LNURL');
|
||||||
@ -31,7 +51,7 @@ export const LnUrlCard = () => {
|
|||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
}
|
}
|
||||||
if (tag === 'login') {
|
if (tag === 'login') {
|
||||||
toast.warning('LnAuth is not available yet');
|
auth({ variables: { url: urlString } });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Problem decoding LNURL');
|
toast.error('Problem decoding LNURL');
|
||||||
@ -43,7 +63,7 @@ export const LnUrlCard = () => {
|
|||||||
<Card>
|
<Card>
|
||||||
<InputWithDeco
|
<InputWithDeco
|
||||||
value={lnurl}
|
value={lnurl}
|
||||||
placeholder={'LnPay or LnWithdraw URL'}
|
placeholder={'LnPay / LnWithdraw / LnAuth'}
|
||||||
title={'LNURL'}
|
title={'LNURL'}
|
||||||
inputCallback={value => setLnUrl(value)}
|
inputCallback={value => setLnUrl(value)}
|
||||||
onEnter={() => handleDecode()}
|
onEnter={() => handleDecode()}
|
||||||
@ -51,7 +71,7 @@ export const LnUrlCard = () => {
|
|||||||
<ColorButton
|
<ColorButton
|
||||||
arrow={true}
|
arrow={true}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
disabled={!lnurl}
|
disabled={!lnurl || loading}
|
||||||
withMargin={'16px 0 0'}
|
withMargin={'16px 0 0'}
|
||||||
onClick={() => handleDecode()}
|
onClick={() => handleDecode()}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user