-
Notifications
You must be signed in to change notification settings - Fork 0
chore: develop → main 릴리즈 (FE 보고 버그 3건 수정) #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5d82e58
fix(auth): 카카오 OIDC scope를 provider별로 분리 (KOE205 invalid_scope 수정)
chanwoo7 5c2997f
fix(auth): 가입 시 자동 nickname sanitize (공백/특수문자 제거 + 길이/유니크 보장)
chanwoo7 4e4df3e
fix(user): 프로필 이미지 URL이 발급된 S3 객체인지 검증 (임의 URL 저장 방지)
chanwoo7 f1242f5
fix(user): 프로필 이미지 URL 검증을 path-traversal 방어로 강화 (URL 파싱·정규화 pathname…
chanwoo7 b5000e7
Merge pull request #142 from CaQuick/fix/fe-reported-auth-signup-profile
chanwoo7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { buildInitialNickname } from '@/features/auth/helpers/initial-nickname.helper'; | ||
|
|
||
| // 앱 nickname 정책(영문/숫자/한글/_) — 생성 결과가 항상 이를 만족해야 한다. | ||
| const NICKNAME_REGEX = /^[A-Za-z0-9가-힣_]+$/; | ||
|
|
||
| describe('buildInitialNickname', () => { | ||
| it('공백 포함 이름은 공백을 제거하고 accountId suffix 를 붙인다', () => { | ||
| expect(buildInitialNickname(5n, 'John Doe')).toBe('JohnDoe_5'); | ||
| }); | ||
|
|
||
| it('특수문자는 제거한다', () => { | ||
| expect(buildInitialNickname(7n, 'user@123!')).toBe('user123_7'); | ||
| }); | ||
|
|
||
| it('한글 이름은 유지한다', () => { | ||
| expect(buildInitialNickname(9n, '김 철수')).toBe('김철수_9'); | ||
| }); | ||
|
|
||
| it('표시 이름이 비거나 모두 특수문자면 이메일 local part 를 정제해 사용한다', () => { | ||
| expect(buildInitialNickname(3n, '!!!', 'john.doe@example.com')).toBe( | ||
| 'johndoe_3', | ||
| ); | ||
| }); | ||
|
|
||
| it('이름·이메일이 모두 없거나 무효면 user 로 폴백한다', () => { | ||
| expect(buildInitialNickname(11n)).toBe('user_11'); | ||
| expect(buildInitialNickname(12n, ' ', '@@@')).toBe('user_12'); | ||
| }); | ||
|
|
||
| it('VarChar(50) 한도 내로 clamp 하되 accountId suffix 는 보존한다', () => { | ||
| const longName = 'a'.repeat(100); | ||
| const result = buildInitialNickname(123n, longName); | ||
| expect(result.length).toBeLessThanOrEqual(50); | ||
| expect(result.endsWith('_123')).toBe(true); | ||
| }); | ||
|
|
||
| it('생성 결과는 항상 nickname 정책(regex)을 만족한다', () => { | ||
| const cases: [bigint, string | undefined, string | undefined][] = [ | ||
| [1n, 'John Doe', undefined], | ||
| [2n, 'user@!#$', 'a.b+c@x.com'], | ||
| [3n, '김 철수 ', undefined], | ||
| [4n, undefined, undefined], | ||
| ]; | ||
| for (const [id, name, email] of cases) { | ||
| expect(buildInitialNickname(id, name, email)).toMatch(NICKNAME_REGEX); | ||
| } | ||
| }); | ||
|
|
||
| it('서로 다른 accountId 는 서로 다른 nickname 을 만든다 (유니크 보장)', () => { | ||
| expect(buildInitialNickname(1n, '철수')).not.toBe( | ||
| buildInitialNickname(2n, '철수'), | ||
| ); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // UserProfile.nickname 컬럼 한도 (prisma schema: VarChar(50)). | ||
| const MAX_NICKNAME_LENGTH = 50; | ||
|
|
||
| // 앱 nickname 정책과 동일한 허용 문자 집합(영문/숫자/한글/_) 외 문자. | ||
| const DISALLOWED_CHARS = /[^A-Za-z0-9가-힣_]/g; | ||
|
|
||
| /** | ||
| * OIDC 최초 가입 시 사용할 임시 nickname 을 생성한다. | ||
| * (사용자는 온보딩에서 본인 nickname 으로 교체한다.) | ||
| * | ||
| * provider 가 주는 이름/이메일에는 공백·특수문자가 있거나, 길이가 길거나, 흔한 이름이 | ||
| * 겹칠 수 있다. 이를 그대로 쓰면 (a) nickname 정책 위반 값 저장, (b) VarChar(50) 초과 | ||
| * insert 실패, (c) unique 제약 충돌로 가입 실패가 발생한다. 이를 모두 방지한다: | ||
| * - 허용 문자만 남기고 제거(공백/특수문자 제거) | ||
| * - `_{accountId}`(PK) suffix 로 유일성 보장 | ||
| * - VarChar(50) 한도 내로 clamp (suffix 는 보존) | ||
| * | ||
| * @param accountId 생성된 계정 PK (유일성 보장에 사용) | ||
| * @param displayName provider 표시 이름 (kakao nickname / google name 등) | ||
| * @param email provider 이메일 (표시 이름이 없을 때 local part 사용) | ||
| */ | ||
| export function buildInitialNickname( | ||
| accountId: bigint, | ||
| displayName?: string, | ||
| email?: string, | ||
| ): string { | ||
| const sanitize = (raw: string): string => raw.replace(DISALLOWED_CHARS, ''); | ||
|
|
||
| const fromName = sanitize(displayName?.trim() ?? ''); | ||
| const fromEmail = email ? sanitize(email.split('@')[0]) : ''; | ||
| const base = fromName || fromEmail || 'user'; | ||
|
|
||
| const suffix = `_${accountId.toString()}`; | ||
| const baseMaxLength = Math.max(0, MAX_NICKNAME_LENGTH - suffix.length); | ||
| return `${base.slice(0, baseMaxLength)}${suffix}`; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Kakao authorization requests that explicitly ask for additional consent items, Kakao's REST API docs show the
scopevalue as comma-delimited (and note OIDC requests must includeopenidwhenscopeis present), whileopenid-clientwill send this string unchanged asscope=openid%20account_email.... In that Kakao login path this can still be parsed as an invalid/single consent scope and reproduce the KOE205 failure this change is trying to fix; the Kakao default (and example override) should use commas, e.g.openid,account_email,profile_nickname,profile_image.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
false positive. 카카오 OIDC scope는 OIDC 표준대로 공백 구분이 맞음(RFC 6749 + 카카오 OIDC 문서 'space-delimited' + 토큰 응답 scope도 공백: 'profile_image openid profile_nickname' + next-auth/openid-client 동일 사용). 콤마로 주면 openid-client가 %2C로 인코딩→카카오가 단일 무효 scope로 파싱→오히려 KOE205. 콤마 표기는 카카오 레거시 REST API 한정.