forked from LaconicNetwork/icns-frontend
Fix some logic handling error
This commit is contained in:
parent
da01e40550
commit
d33788e2b1
@ -23,7 +23,8 @@ class ErrorBoundary extends Component<Props, State> {
|
|||||||
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||||
console.error("Uncaught error:", error, errorInfo);
|
console.error("Uncaught error:", error, errorInfo);
|
||||||
|
|
||||||
captureException(error);
|
const errorMessage = error.message || error;
|
||||||
|
captureException(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
...(!!process.env.NEXT_PUBLIC_SENTRY_DSN && {
|
||||||
sentry: {
|
sentry: {
|
||||||
hideSourceMaps: true,
|
hideSourceMaps: true,
|
||||||
},
|
},
|
||||||
api: {
|
}),
|
||||||
externalResolver: true,
|
|
||||||
},
|
|
||||||
reactStrictMode: false,
|
reactStrictMode: false,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
compiler: {
|
compiler: {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
import { captureException } from "@sentry/nextjs";
|
||||||
import { withIronSessionApiRoute } from "iron-session/next";
|
import { withIronSessionApiRoute } from "iron-session/next";
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { ironOptions } from "../../iron.config";
|
import { ironOptions } from "../../iron.config";
|
||||||
import { IcnsVerificationResponse } from "../../types";
|
|
||||||
import { request } from "../../utils/url";
|
|
||||||
|
|
||||||
export default withIronSessionApiRoute(async function handler(
|
export default withIronSessionApiRoute(async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
@ -10,30 +9,42 @@ export default withIronSessionApiRoute(async function handler(
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (!process.env.ICNS_VERIFIER_ORIGIN_LIST) {
|
if (!process.env.ICNS_VERIFIER_ORIGIN_LIST) {
|
||||||
console.log(".env is not set");
|
const errorMessage = ".env is not set";
|
||||||
|
console.error(errorMessage);
|
||||||
|
captureException(errorMessage);
|
||||||
return res.status(500).json({ error: "Internal server error" });
|
return res.status(500).json({ error: "Internal server error" });
|
||||||
}
|
}
|
||||||
const verifierOriginList = process.env.ICNS_VERIFIER_ORIGIN_LIST.split(",");
|
const verifierOriginList = process.env.ICNS_VERIFIER_ORIGIN_LIST.split(",");
|
||||||
|
|
||||||
const verificationList = await Promise.allSettled(
|
const verificationList = await Promise.allSettled(
|
||||||
verifierOriginList.map((verfierOrigin) =>
|
verifierOriginList.map(async (verfierOrigin) =>
|
||||||
request<IcnsVerificationResponse>(
|
(
|
||||||
`${verfierOrigin}/api/verify_twitter`,
|
await fetch(`${verfierOrigin}/api/verify_twitter`, {
|
||||||
{
|
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(req.body),
|
body: JSON.stringify(req.body),
|
||||||
},
|
})
|
||||||
),
|
).json(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const errorTrimmedVerificationList = verificationList.map(
|
||||||
|
(verification) => ({
|
||||||
|
...verification,
|
||||||
|
...(verification.status === "rejected" && {
|
||||||
|
reason: verification.reason.message || verification.reason,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
verificationList,
|
verificationList: errorTrimmedVerificationList,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
captureException(error);
|
||||||
res.status(500).json({ error: "Internal server error" });
|
res.status(500).json({ error: "Internal server error" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import { captureException } from "@sentry/nextjs";
|
||||||
import { withIronSessionApiRoute } from "iron-session/next";
|
import { withIronSessionApiRoute } from "iron-session/next";
|
||||||
import { request } from "../../utils/url";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { ironOptions } from "../../iron.config";
|
|
||||||
import { twitterApiBaseUrl } from "../../constants/twitter";
|
import { twitterApiBaseUrl } from "../../constants/twitter";
|
||||||
|
import { ironOptions } from "../../iron.config";
|
||||||
|
|
||||||
export default withIronSessionApiRoute(async function handler(
|
export default withIronSessionApiRoute(async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
@ -45,10 +45,11 @@ export default withIronSessionApiRoute(async function handler(
|
|||||||
params.append("code_verifier", req.session.code_verifier);
|
params.append("code_verifier", req.session.code_verifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { access_token: accessToken, refresh_token } =
|
const {
|
||||||
await request<TwitterOAuth2TokenResponse>(
|
access_token: accessToken,
|
||||||
`${twitterApiBaseUrl}/oauth2/token`,
|
refresh_token,
|
||||||
{
|
}: TwitterOAuth2TokenResponse = await (
|
||||||
|
await fetch(`${twitterApiBaseUrl}/oauth2/token`, {
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
@ -57,41 +58,47 @@ export default withIronSessionApiRoute(async function handler(
|
|||||||
).toString("base64")}`,
|
).toString("base64")}`,
|
||||||
},
|
},
|
||||||
body: params,
|
body: params,
|
||||||
},
|
})
|
||||||
);
|
).json();
|
||||||
|
|
||||||
req.session.refresh_token = refresh_token;
|
req.session.refresh_token = refresh_token;
|
||||||
await req.session.save();
|
await req.session.save();
|
||||||
const {
|
const { data, title }: TwitterUsersMeResponse = await (
|
||||||
data: {
|
await fetch(
|
||||||
id,
|
|
||||||
username,
|
|
||||||
name,
|
|
||||||
profile_image_url,
|
|
||||||
description,
|
|
||||||
public_metrics,
|
|
||||||
},
|
|
||||||
} = await request<TwitterUsersMeResponse>(
|
|
||||||
`${twitterApiBaseUrl}/users/me?user.fields=profile_image_url,public_metrics,description`,
|
`${twitterApiBaseUrl}/users/me?user.fields=profile_image_url,public_metrics,description`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${accessToken}`,
|
Authorization: `Bearer ${accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
).json();
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
username,
|
||||||
|
name,
|
||||||
|
profile_image_url,
|
||||||
|
description,
|
||||||
|
public_metrics,
|
||||||
|
} = data || {};
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
accessToken,
|
accessToken,
|
||||||
id,
|
id,
|
||||||
username,
|
username,
|
||||||
name,
|
name,
|
||||||
profile_image_url: profile_image_url.replace("normal.jpg", "400x400.jpg"),
|
profile_image_url: profile_image_url?.replace(
|
||||||
|
"normal.jpg",
|
||||||
|
"400x400.jpg",
|
||||||
|
),
|
||||||
description,
|
description,
|
||||||
public_metrics,
|
public_metrics,
|
||||||
|
error: title,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
res.status(500).json({ error: "Internal server error " });
|
captureException(error);
|
||||||
|
res.status(500).json({ error: "Internal Server Error" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ironOptions);
|
ironOptions);
|
||||||
@ -105,7 +112,7 @@ interface TwitterOAuth2TokenResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TwitterUsersMeResponse {
|
interface TwitterUsersMeResponse {
|
||||||
data: {
|
data?: {
|
||||||
id: string;
|
id: string;
|
||||||
username: string;
|
username: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -113,6 +120,11 @@ interface TwitterUsersMeResponse {
|
|||||||
description: string;
|
description: string;
|
||||||
public_metrics: TwitterPublicMetrics;
|
public_metrics: TwitterPublicMetrics;
|
||||||
};
|
};
|
||||||
|
// Error data
|
||||||
|
title?: string;
|
||||||
|
detail?: string;
|
||||||
|
type?: string;
|
||||||
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TwitterPublicMetrics {
|
export interface TwitterPublicMetrics {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import { captureException } from "@sentry/nextjs";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { withIronSessionApiRoute } from "iron-session/next";
|
import { withIronSessionApiRoute } from "iron-session/next";
|
||||||
import { base64URLEncode } from "../../utils/encoding";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { buildQueryString } from "../../utils/url";
|
|
||||||
import { ironOptions } from "../../iron.config";
|
|
||||||
import {
|
import {
|
||||||
twitterOAuthBaseUrl,
|
twitterOAuthBaseUrl,
|
||||||
twitterOAuthScopes,
|
twitterOAuthScopes,
|
||||||
} from "../../constants/twitter";
|
} from "../../constants/twitter";
|
||||||
|
import { ironOptions } from "../../iron.config";
|
||||||
|
import { base64URLEncode } from "../../utils/encoding";
|
||||||
|
import { buildQueryString } from "../../utils/url";
|
||||||
|
|
||||||
export default withIronSessionApiRoute(async function handler(
|
export default withIronSessionApiRoute(async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
@ -46,6 +47,7 @@ export default withIronSessionApiRoute(async function handler(
|
|||||||
res.status(200).json({ authUrl });
|
res.status(200).json({ authUrl });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
captureException(error);
|
||||||
res.status(500).json({ error: "Internal server error" });
|
res.status(500).json({ error: "Internal server error" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -239,13 +239,12 @@ export default function VerificationPage() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
if (error.message === TWITTER_LOGIN_ERROR) {
|
setErrorMessage({ message: error.message, path: "/" });
|
||||||
setErrorMessage({ message: TWITTER_LOGIN_ERROR, path: "/" });
|
|
||||||
setErrorModalOpen(true);
|
setErrorModalOpen(true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
captureException(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingInit(false);
|
setIsLoadingInit(false);
|
||||||
}
|
}
|
||||||
@ -404,8 +403,7 @@ export default function VerificationPage() {
|
|||||||
|
|
||||||
if (verification.status === "rejected") {
|
if (verification.status === "rejected") {
|
||||||
if (verification.reason) {
|
if (verification.reason) {
|
||||||
const errorMessage =
|
const errorMessage = verification.reason;
|
||||||
verification.reason.message || verification.reason;
|
|
||||||
captureException(errorMessage);
|
captureException(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,8 +441,6 @@ export default function VerificationPage() {
|
|||||||
rest: REST_URL,
|
rest: REST_URL,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(aminoMsgs);
|
|
||||||
|
|
||||||
const simulated = await simulateMsgs(
|
const simulated = await simulateMsgs(
|
||||||
chainInfo,
|
chainInfo,
|
||||||
walletKey.bech32Address,
|
walletKey.bech32Address,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
IcnsVerificationResponse,
|
IcnsVerificationResponseOnFrontend,
|
||||||
TwitterAuthInfoResponse,
|
TwitterAuthInfoResponse,
|
||||||
TwitterAuthUrlResponse,
|
TwitterAuthUrlResponse,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
@ -27,7 +27,9 @@ export const verifyTwitterAccount = async (
|
|||||||
accessToken: string,
|
accessToken: string,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
await request<IcnsVerificationResponse>("/api/icns-verification", {
|
await request<IcnsVerificationResponseOnFrontend>(
|
||||||
|
"/api/icns-verification",
|
||||||
|
{
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@ -36,6 +38,7 @@ export const verifyTwitterAccount = async (
|
|||||||
claimer: claimer,
|
claimer: claimer,
|
||||||
authToken: accessToken,
|
authToken: accessToken,
|
||||||
}),
|
}),
|
||||||
})
|
},
|
||||||
|
)
|
||||||
).verificationList;
|
).verificationList;
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,30 @@ export interface IcnsVerificationResponse {
|
|||||||
)[];
|
)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IcnsVerificationResponseOnFrontend {
|
||||||
|
verificationList: (
|
||||||
|
| {
|
||||||
|
status: "fulfilled";
|
||||||
|
value: {
|
||||||
|
errors: Error[];
|
||||||
|
data: {
|
||||||
|
// JSON string
|
||||||
|
verifying_msg: string;
|
||||||
|
// Base64 encoded
|
||||||
|
public_key: string;
|
||||||
|
// Base64 encoded
|
||||||
|
signature: string;
|
||||||
|
algorithm: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
status: "rejected";
|
||||||
|
reason: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface NameByTwitterIdQueryResponse {
|
export interface NameByTwitterIdQueryResponse {
|
||||||
data: {
|
data: {
|
||||||
name: string;
|
name: string;
|
||||||
|
29
utils/url.ts
29
utils/url.ts
@ -2,23 +2,32 @@ import { TwitterLoginSuccess } from "../types";
|
|||||||
import { TWITTER_LOGIN_ERROR } from "../constants/error-message";
|
import { TWITTER_LOGIN_ERROR } from "../constants/error-message";
|
||||||
import { WALLET_INSTALL_URL } from "../constants/wallet";
|
import { WALLET_INSTALL_URL } from "../constants/wallet";
|
||||||
|
|
||||||
export function request<TResponse>(
|
export async function request<TResponse>(
|
||||||
url: string,
|
url: string,
|
||||||
config: RequestInit = {},
|
config: RequestInit = {},
|
||||||
customConfig?: {
|
customConfig?: {
|
||||||
isErrorIgnore?: boolean;
|
isErrorIgnore?: boolean;
|
||||||
},
|
},
|
||||||
): Promise<TResponse> {
|
): Promise<TResponse> {
|
||||||
return fetch(url, config)
|
const response = await fetch(url, config);
|
||||||
.then((response) => {
|
const data = await response.json();
|
||||||
if (!response.ok && !customConfig?.isErrorIgnore) {
|
|
||||||
throw new Error(
|
if (
|
||||||
`This is an HTTP error: The status is ${response.status} ${response.statusText}`,
|
(!response.ok || data.error || data.errors) &&
|
||||||
);
|
!customConfig?.isErrorIgnore
|
||||||
|
) {
|
||||||
|
const { error, errors } = data;
|
||||||
|
let errorMessage;
|
||||||
|
if (error && error.error) {
|
||||||
|
errorMessage = error.error_description;
|
||||||
|
} else {
|
||||||
|
errorMessage =
|
||||||
|
(error && error.toString()) || (errors && errors.toString());
|
||||||
}
|
}
|
||||||
return response.json();
|
throw new Error(errorMessage);
|
||||||
})
|
}
|
||||||
.then((data) => data as TResponse);
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildQueryString(query: Record<string, any>): string {
|
export function buildQueryString(query: Record<string, any>): string {
|
||||||
|
Loading…
Reference in New Issue
Block a user