FastComments.com

FastComments๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ“๊ธ€์ด ์‹œ์Šคํ…œ์— ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜, ์—…๋ฐ์ดํŠธ๋˜๊ฑฐ๋‚˜, ์ œ๊ฑฐ๋  ๋•Œ๋งˆ๋‹ค API ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๋ฅผ HTTP/HTTPS๋ฅผ ํ†ตํ•œ ๋น„๋™๊ธฐ ์›นํ›„ํฌ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์›นํ›„ํฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€ Internal Link


์›นํ›…์€ ๋‘ ์‹œ์Šคํ…œ ๊ฐ„์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋˜๋Š” ํ†ตํ•ฉ์œผ๋กœ, "์ƒ์‚ฐ์ž" (FastComments)๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  "์†Œ๋น„์ž" (์‚ฌ์šฉ์ž)๊ฐ€ API ํ˜ธ์ถœ์„ ํ†ตํ•ด ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ์†Œ๋น„ํ•ฉ๋‹ˆ๋‹ค.


์ง€์›๋˜๋Š” ์ด๋ฒคํŠธ ๋ฐ ๋ฆฌ์†Œ์Šค Internal Link


FastComments๋Š” Comment ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•ด์„œ๋งŒ ์›นํ›…์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋Œ“๊ธ€ ์ƒ์„ฑ, ์‚ญ์ œ ๋ฐ ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•œ ์›นํ›…์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ด๋“ค ๊ฐ๊ฐ์€ ์‹œ์Šคํ…œ์—์„œ ๋ณ„๊ฐœ์˜ ์ด๋ฒคํŠธ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ, ๋”ฐ๋ผ์„œ ์›นํ›… ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์˜๋ฏธ ์™€ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.


ํ…Œ์ŠคํŠธ Internal Link

Webhooks ๊ด€๋ฆฌ์ž์—๋Š” ๊ฐ ์ด๋ฒคํŠธ ์œ ํ˜• (Create, Update, Delete)์— ๋Œ€ํ•ด Send Test Payload ๋ฒ„ํŠผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Create ๋ฐ Update ์ด๋ฒคํŠธ๋Š” ๋”๋ฏธ WebhookComment ๊ฐ์ฒด๋ฅผ ์ „์†กํ•˜๋ฉฐ, Delete ํ…Œ์ŠคํŠธ๋Š” ID๋งŒ ์žˆ๋Š” ๋”๋ฏธ ์š”์ฒญ ๋ณธ๋ฌธ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

ํŽ˜์ด๋กœ๋“œ ๊ฒ€์ฆ

์›นํ›… ํ†ตํ•ฉ์„ ํ…Œ์ŠคํŠธํ•  ๋•Œ, ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์— ๋‹ค์Œ ํ—ค๋”๋“ค์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:

  1. token - ๊ท€ํ•˜์˜ API ๋น„๋ฐ€
  2. X-FastComments-Timestamp - Unix ํƒ€์ž„์Šคํƒฌํ”„(์ดˆ)
  3. X-FastComments-Signature - HMAC-SHA256 ์„œ๋ช…

HMAC ์„œ๋ช… ๊ฒ€์ฆ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด๋กœ๋“œ์˜ ์ง„์œ„๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

ํ…Œ์ŠคํŠธ ๋„๊ตฌ

๊ฐœ๋ฐœ ์ค‘ ๋“ค์–ด์˜ค๋Š” ์›นํ›… ํŽ˜์ด๋กœ๋“œ๋ฅผ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•ด webhook.site ๋˜๋Š” ngrok๊ณผ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ์œ ํ˜•

  • Create Event: ์ƒˆ ๋Œ“๊ธ€์ด ์ƒ์„ฑ๋  ๋•Œ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ: PUT
  • Update Event: ๋Œ“๊ธ€์ด ํŽธ์ง‘๋  ๋•Œ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ: PUT
  • Delete Event: ๋Œ“๊ธ€์ด ์‚ญ์ œ๋  ๋•Œ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ: DELETE

๊ฐ ์ด๋ฒคํŠธ๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์— ์ „์ฒด ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค (ํŽ˜์ด๋กœ๋“œ ํ˜•์‹์€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ฐธ์กฐ).

๋ฐ์ดํ„ฐ ๊ตฌ์กฐ Internal Link

์›นํ›„ํฌ๋กœ ์ „์†ก๋˜๋Š” ์œ ์ผํ•œ ๊ตฌ์กฐ๋Š” ์•„๋ž˜ TypeScript์— ์„ค๋ช…๋œ WebhookComment ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

WebhookComment ๊ฐ์ฒด ๊ตฌ์กฐ

"Create" ์ด๋ฒคํŠธ ๊ตฌ์กฐ

"create" ์ด๋ฒคํŠธ ์š”์ฒญ ๋ณธ๋ฌธ์€ WebhookComment ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

"Update" ์ด๋ฒคํŠธ ๊ตฌ์กฐ

"update" ์ด๋ฒคํŠธ ์š”์ฒญ ๋ณธ๋ฌธ์€ WebhookComment ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

"Delete" ์ด๋ฒคํŠธ ๊ตฌ์กฐ

"delete" ์ด๋ฒคํŠธ ์š”์ฒญ ๋ณธ๋ฌธ์€ WebhookComment ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ โ€” 2023๋…„ 11์›” 14์ผ ๊ธฐ์ค€
์ด์ „์—๋Š” "delete" ์ด๋ฒคํŠธ ์š”์ฒญ ๋ณธ๋ฌธ์— ๋Œ“๊ธ€ id๋งŒ ํฌํ•จ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์‚ญ์ œ ์‹œ์ ์˜ ์ „์ฒด ๋Œ“๊ธ€์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
WebhookComment ๊ฐ์ฒด
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** ๋Œ“๊ธ€์˜ id. **/
4 id: string
5 /** ๋Œ“๊ธ€ ์Šค๋ ˆ๋“œ๋ฅผ ์‹๋ณ„ํ•˜๋Š” id ๋˜๋Š” URL. ์ •๊ทœํ™”๋จ. **/
6 urlId: string
7 /** ๋Œ“๊ธ€์ด ๋‚จ๊ฒจ์ง„ ์œ„์น˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” URL. **/
8 url?: string
9 /** ๋Œ“๊ธ€์„ ๋‚จ๊ธด ์‚ฌ์šฉ์ž์˜ id. SSO์ธ ๊ฒฝ์šฐ tenant id๊ฐ€ ์ ‘๋‘์‚ฌ๋กœ ๋ถ™์Šต๋‹ˆ๋‹ค. **/
10 userId?: string
11 /** ๋Œ“๊ธ€์„ ๋‚จ๊ธด ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ. **/
12 commenterEmail?: string
13 /** ๋Œ“๊ธ€ ์œ„์ ฏ์— ํ‘œ์‹œ๋˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„. SSO์˜ ๊ฒฝ์šฐ displayName์ผ ์ˆ˜ ์žˆ์Œ. **/
14 commenterName: string
15 /** ์›์‹œ ๋Œ“๊ธ€ ํ…์ŠคํŠธ. **/
16 comment: string
17 /** ํŒŒ์‹ฑ ํ›„์˜ ๋Œ“๊ธ€ ํ…์ŠคํŠธ. **/
18 commentHTML: string
19 /** ์™ธ๋ถ€ ๋Œ“๊ธ€ id. **/
20 externalId?: string
21 /** ๋ถ€๋ชจ ๋Œ“๊ธ€์˜ id. **/
22 parentId?: string | null
23 /** ๋Œ“๊ธ€์ด ์ž‘์„ฑ๋œ UTC ๋‚ ์งœ. **/
24 date: UTC_ISO_DateString
25 /** ํˆฌํ‘œ์˜ ํ•ฉ์‚ฐ ์ ์ˆ˜ (์ฐฌ์„ฑ - ๋ฐ˜๋Œ€). **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** ์‚ฌ์šฉ์ž๊ฐ€ ๋Œ“๊ธ€ ์ž‘์„ฑ ๋‹น์‹œ ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ์—ˆ๊ฑฐ๋‚˜, ๋Œ“๊ธ€์ด ์ธ์ฆ๋˜์—ˆ๊ฑฐ๋‚˜, ์„ธ์…˜์„ ์ธ์ฆํ•œ ๊ฒฝ์šฐ true. **/
30 verified: boolean
31 /** ๋Œ“๊ธ€์ด ์ธ์ฆ๋œ ๋‚ ์งœ. **/
32 verifiedDate?: number
33 /** ๋ชจ๋”๋ ˆ์ดํ„ฐ๊ฐ€ ๋Œ“๊ธ€์„ ๊ฒ€ํ† ๋จ์œผ๋กœ ํ‘œ์‹œํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€. **/
34 reviewed: boolean
35 /** ์•„๋ฐ”ํƒ€์˜ ์œ„์น˜ ๋˜๋Š” base64 ์ธ์ฝ”๋”ฉ. SSO๋กœ ์ „๋‹ฌ๋œ ๊ฐ’์ด base64์˜€๋˜ ๊ฒฝ์šฐ์—๋งŒ base64๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. **/
36 avatarSrc?: string
37 /** ๋Œ“๊ธ€์ด ์ˆ˜๋™์œผ๋กœ ๋˜๋Š” ์ž๋™์œผ๋กœ ์ŠคํŒธ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€. **/
38 isSpam: boolean
39 /** ๋Œ“๊ธ€์ด ์ž๋™์œผ๋กœ ์ŠคํŒธ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€. **/
40 aiDeterminedSpam: boolean
41 /** ๋Œ“๊ธ€์— ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€. **/
42 hasImages: boolean
43 /** 'Most Relevant' ์ •๋ ฌ์—์„œ ๋Œ“๊ธ€์ด ์œ„์น˜ํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ. **/
44 pageNumber: number
45 /** 'Oldest First' ์ •๋ ฌ์—์„œ ๋Œ“๊ธ€์ด ์œ„์น˜ํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ. **/
46 pageNumberOF: number
47 /** 'Newest First' ์ •๋ ฌ์—์„œ ๋Œ“๊ธ€์ด ์œ„์น˜ํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ. **/
48 pageNumberNF: number
49 /** ๋Œ“๊ธ€์ด ์ž๋™์œผ๋กœ ์Šน์ธ๋˜์—ˆ๋Š”์ง€ ๋˜๋Š” ์ˆ˜๋™์œผ๋กœ ์Šน์ธ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€. **/
50 approved: boolean
51 /** ๋Œ“๊ธ€ ์ž‘์„ฑ ๋‹น์‹œ ์‚ฌ์šฉ์ž์˜ ๋กœ์ผ€์ผ ์ฝ”๋“œ(ํ˜•์‹: en_us). **/
52 locale: string
53 /** ๋Œ“๊ธ€์—์„œ ์„ฑ๊ณต์ ์œผ๋กœ ํŒŒ์‹ฑ๋œ @๋ฉ˜์…˜ ๋ชฉ๋ก. **/
54 mentions?: CommentUserMention[]
55 /** ๋Œ“๊ธ€์ด ์ž‘์„ฑ๋œ ๋„๋ฉ”์ธ. **/
56 domain?: string
57 /** ์ด ๋Œ“๊ธ€์— ์—ฐ๊ฒฐ๋œ ์„ ํƒ์  ๋ชจ๋”๋ ˆ์ด์…˜ ๊ทธ๋ฃน id ๋ชฉ๋ก. **/
58 moderationGroupIds?: string[]|null
59}
60

When users are tagged in a comment, the information is stored in a list called mentions. Each object in that list has the following structure.

Webhook Mentions ๊ฐ์ฒด
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** ์‚ฌ์šฉ์ž id. SSO ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ tenant id๊ฐ€ ์ ‘๋‘์‚ฌ๋กœ ๋ถ™์Šต๋‹ˆ๋‹ค. **/
4 id: string
5 /** @ ๊ธฐํ˜ธ๋ฅผ ํฌํ•จํ•œ ์ตœ์ข… @๋ฉ˜์…˜ ํƒœ๊ทธ ํ…์ŠคํŠธ. **/
6 tag: string
7 /** @ ๊ธฐํ˜ธ๋ฅผ ํฌํ•จํ•œ ์›๋ณธ @๋ฉ˜์…˜ ํƒœ๊ทธ ํ…์ŠคํŠธ. **/
8 rawTag: string
9 /** ํƒœ๊ทธ๋œ ์‚ฌ์šฉ์ž์˜ ์œ ํ˜•. user = FastComments.com ๊ณ„์ •. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ์ˆ˜์‹ ์„ ๊ฑฐ๋ถ€ํ•˜๋”๋ผ๋„ ์ด ๊ฐ’์€ true๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. **/
12 sent: boolean
13}
14

HTTP ๋ฉ”์„œ๋“œ

๊ด€๋ฆฌ์ž ํŒจ๋„์—์„œ ๊ฐ ์›นํ›„ํฌ ์ด๋ฒคํŠธ ์œ ํ˜•์— ๋Œ€ํ•œ HTTP ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • Create Event: POST ๋˜๋Š” PUT (๊ธฐ๋ณธ๊ฐ’: PUT)
  • Update Event: POST ๋˜๋Š” PUT (๊ธฐ๋ณธ๊ฐ’: PUT)
  • Delete Event: DELETE, POST ๋˜๋Š” PUT (๊ธฐ๋ณธ๊ฐ’: DELETE)

๋ชจ๋“  ์š”์ฒญ์— ID๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ Create ๋ฐ Update ์ž‘์—…์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉฑ๋“ฑํ•ฉ๋‹ˆ๋‹ค (PUT). ๋™์ผํ•œ Create ๋˜๋Š” Update ์š”์ฒญ์„ ๋ฐ˜๋ณตํ•ด๋„ ๊ท€์ธก์—์„œ ์ค‘๋ณต ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ ํ—ค๋”

๊ฐ ์›นํ›„ํฌ ์š”์ฒญ์—๋Š” ๋‹ค์Œ ํ—ค๋”๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค:

Header Description
Content-Type application/json
token ๊ท€ํ•˜์˜ API ์‹œํฌ๋ฆฟ
X-FastComments-Timestamp ์š”์ฒญ์ด ์„œ๋ช…๋œ ์‹œ์ ์˜ Unix ํƒ€์ž„์Šคํƒฌํ”„(์ดˆ)
X-FastComments-Signature HMAC-SHA256 ์„œ๋ช… (sha256=<hex>)

HMAC ์„œ๋ช… ๊ฒ€์ฆ์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ๋ณด์•ˆ ๋ฐ API ํ† ํฐ์—์„œ ํ™•์ธํ•˜์„ธ์š”.


๋ณด์•ˆ ๋ฐ API ํ† ํฐ Internal Link


FastComments ์›นํ›… ์š”์ฒญ์—๋Š” ๋ณด์•ˆ์„ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์ธ์ฆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ „์†ก๋˜๋Š” ํ—ค๋”

ํ—ค๋” ์„ค๋ช…
token ๊ท€ํ•˜์˜ API Secret(ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์šฉ)
X-FastComments-Timestamp ์š”์ฒญ์ด ์„œ๋ช…๋  ๋•Œ์˜ Unix ํƒ€์ž„์Šคํƒฌํ”„(์ดˆ)
X-FastComments-Signature ํŽ˜์ด๋กœ๋“œ์˜ HMAC-SHA256 ์„œ๋ช…

HMAC ์„œ๋ช… ๊ฒ€์ฆ (๊ถŒ์žฅ)

์›นํ›… ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์ง„๋ณธ์ด๋ฉฐ ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด HMAC ์„œ๋ช… ๊ฒ€์ฆ์„ ๊ฐ•๋ ฅํžˆ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์„œ๋ช… ํ˜•์‹: sha256=<hex-encoded-signature>

์„œ๋ช…์ด ๊ณ„์‚ฐ๋˜๋Š” ๋ฐฉ๋ฒ•:

  1. ๊ฒฐํ•ฉ: timestamp + "." + JSON_payload_body
  2. API Secret์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜์—ฌ HMAC-SHA256์„ ๊ณ„์‚ฐ
  3. ๊ฒฐ๊ณผ๋ฅผ 16์ง„์ˆ˜๋กœ ์ธ์ฝ”๋”ฉ

์˜ˆ์‹œ ๊ฒ€์ฆ (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(req, apiSecret) {
    const timestamp = req.headers['x-fastcomments-timestamp'];
    const signature = req.headers['x-fastcomments-signature'];

    if (!timestamp || !signature) {
        return false;
    }

    // ํƒ€์ž„์Šคํƒฌํ”„๊ฐ€ ์ตœ๊ทผ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค (5๋ถ„ ์ด๋‚ด)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // ์žฌ์ƒ ๊ณต๊ฒฉ ๋ฐฉ์ง€
    }

    // ์„œ๋ช… ๊ฒ€์ฆ
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

    return signature === `sha256=${expectedSignature}`;
}

์˜ˆ์‹œ ๊ฒ€์ฆ (Python)

import hmac
import hashlib
import time
import json

def verify_webhook_signature(headers, body, api_secret):
    timestamp = headers.get('X-FastComments-Timestamp')
    signature = headers.get('X-FastComments-Signature')

    if not timestamp or not signature:
        return False

    # ํƒ€์ž„์Šคํƒฌํ”„๊ฐ€ ์ตœ์‹ ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # ์„œ๋ช… ๊ฒ€์ฆ
    payload = json.dumps(body, separators=(',', ':'))
    message = f"{timestamp}.{payload}"
    expected = hmac.new(
        api_secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return signature == f"sha256={expected}"

์˜ˆ์‹œ ๊ฒ€์ฆ (PHP)

function verifyWebhookSignature($headers, $body, $apiSecret) {
    $timestamp = $headers['X-FastComments-Timestamp'] ?? null;
    $signature = $headers['X-FastComments-Signature'] ?? null;

    if (!$timestamp || !$signature) {
        return false;
    }

    // ํƒ€์ž„์Šคํƒฌํ”„๊ฐ€ ์ตœ์‹ ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค (5๋ถ„ ์ด๋‚ด)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // ์„œ๋ช… ๊ฒ€์ฆ
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

๋ ˆ๊ฑฐ์‹œ ์ธ์ฆ

ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ๊ท€ํ•˜์˜ API Secret์ด ํฌํ•จ๋œ token ํ—ค๋”๋Š” ์—ฌ์ „ํžˆ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ HMAC ๊ฒ€์ฆ์€ ์žฌ์ƒ ๊ณต๊ฒฉ์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•˜๋ฏ€๋กœ ๋ณด์•ˆ ํ–ฅ์ƒ์„ ์œ„ํ•ด HMAC ๊ฒ€์ฆ์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.



๊ฒฐ๋ก 

์ด๋กœ์จ ์šฐ๋ฆฌ์˜ Webhooks ๋ฌธ์„œ๊ฐ€ ๋งˆ๋ฌด๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

FastComments Webhook ํ†ตํ•ฉ์ด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ์„ค์ •๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋ฌธ์„œ์—์„œ ๋ˆ„๋ฝ๋œ ๋ถ€๋ถ„์„ ๋ฐœ๊ฒฌํ•˜์…จ๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋ฉด ์•„๋ž˜์— ์•Œ๋ ค์ฃผ์„ธ์š”.