Skip to content
Merged
8 changes: 7 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ jobs:
- name: Build
run: yarn build && yarn next export

- name: Prepare deployment package
run: |
mkdir -p deploy
cp -r out/* deploy/
cp -r functions deploy/

- uses: actions/upload-artifact@v4
with:
name: built-app
path: out
path: deploy
if-no-files-found: error
retention-days: 7
19 changes: 19 additions & 0 deletions functions/.well-known/apple-app-site-association.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const APPLE_APP_SITE_ASSOCIATION = `{
"applinks": {
"apps": [],
"details": [
{
"appID": "95YWTT5L8K.com.sopt-stamp-iOS.release",
"paths": ["*"]
}
]
}
}`;

export const onRequest: PagesFunction = () => {
return new Response(APPLE_APP_SITE_ASSOCIATION, {
headers: {
'Content-Type': 'application/json',
},
});
};
21 changes: 21 additions & 0 deletions functions/.well-known/assetlinks.json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const ASSETLINKS_JSON = `[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "org.sopt.official",
"sha256_cert_fingerprints": [
"29:23:1F:E3:7A:FD:76:9C:58:CA:F3:E2:D9:7C:A1:69:CF:04:A8:6E:5B:8A:C6:56:6A:6F:E8:FD:D8:FF:47:43",
"30:8A:35:1F:E1:88:94:6F:BC:E9:B2:D5:FC:2F:9B:F2:10:35:2A:43:B8:36:03:8B:C4:1B:EA:51:23:76:1C:00"
]
}
}
]`;

export const onRequest: PagesFunction = () => {
return new Response(ASSETLINKS_JSON, {
headers: {
'Content-Type': 'application/json',
},
});
};
33 changes: 13 additions & 20 deletions public/.well-known/apple-app-site-association
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
{\rtf1\ansi\ansicpg1252\cocoartf2822
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\froman\fcharset0 Times-Roman;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;}
\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
\deftab720
\pard\pardeftab720\partightenfactor0

\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
\{\
\'93applinks\'94: \{\
\'93apps\'94: [],\
\'93details\'94: [\
\{\
\'93appID\'94: \'9395YWTT5L8K.com.sopt-stamp-iOS.release\'94,\
\'93paths\'94: [\'93*\'94]\
\}\
]\
\}\
\}}
{
"applinks": {
"apps": [],
"details": [
{
"appID": "95YWTT5L8K.com.sopt-stamp-iOS.release",
"paths": [
"*"
]
}
]
}
}
6 changes: 6 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ axiosCrewInstance.interceptors.response.use(
);

export const handleTokenError = async (error: AxiosError<unknown>) => {
console.log(error);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

프로덕션 환경에서 console.log(error) 제거를 권장합니다.

AxiosError 객체에는 config.headers.Authorization에 Bearer 토큰이 포함되어 있어, 전체 에러를 console.log로 출력하면 브라우저 콘솔에 토큰이 노출될 수 있습니다. 디버깅 목적이라면 console.error로 통일하거나, 민감한 정보가 포함되지 않는 메시지만 출력하는 것이 좋습니다.

🔒 제안하는 수정
 export const handleTokenError = async (error: AxiosError<unknown>) => {
-  console.log(error);
+  console.error('API error:', error.message, error.response?.status);
   const originRequest = error.config;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log(error);
export const handleTokenError = async (error: AxiosError<unknown>) => {
console.error('API error:', error.message, error.response?.status);
const originRequest = error.config;
🤖 Prompt for AI Agents
In `@src/api/index.ts` at line 83, Replace the insecure console.log(error) with a
safe error-logging flow: do not print the full AxiosError object (which can
contain config.headers.Authorization); instead sanitize or remove the
Authorization header from error.config before logging and log using
console.error or a structured logger. Specifically, locate the
console.log(error) occurrence and change it to either log only non-sensitive
fields (e.g., error.message, error.response?.status, error.response?.data) or
clone error.config and mask/delete config.headers.Authorization prior to calling
console.error, ensuring no Bearer token is emitted to the browser console.

const originRequest = error.config;

if (!error.response || !originRequest) throw new Error('에러가 발생했습니다.');
Expand All @@ -95,12 +96,17 @@ export const handleTokenError = async (error: AxiosError<unknown>) => {
// 개인정보 처리방침 페이지는 로그인 필요 없음, 구글 정책상 오픈
return Promise.reject(error);
}
// 앱 딥링크를 위한 .well-known 경로는 인증 체크 제외
if (window.location.pathname.startsWith('/.well-known')) {
return Promise.reject(error);
}
/** 토큰이 없으면 refresh 시도하지 않고 바로 intro로 이동 */
const currentToken = tokenStorage.get();
if (currentToken === null && window.location.pathname !== '/intro') {
window.location.replace('/intro');
throw new Error('토큰이 없습니다.');
}

try {
const { data } = await axiosAuthInstance.post<{ data: { accessToken: string } }>(
`/api/v1/auth/refresh/web`,
Expand Down
Loading