Changeset 9e9e6f9 in Klonkt for src/services
- Timestamp:
- 07/21/2026 01:16:03 AM (7 weeks ago)
- Branches:
- main
- Children:
- d43230f
- Parents:
- 928d1c7
- git-author:
- Robin <roboburr@…> (07/21/2026 01:15:39 AM)
- git-committer:
- Robin <roboburr@…> (07/21/2026 01:16:03 AM)
- Location:
- src/services
- Files:
-
- 1 added
- 1 edited
-
PaidPatreonService.js (modified) (2 diffs)
-
PasskeyService.js (added)
Legend:
- Unmodified
- Added
- Removed
-
src/services/PaidPatreonService.js
r928d1c7 r9e9e6f9 124 124 } 125 125 126 // Pure: pick the membership for the owner's campaign out of a Patreon 127 // identity?include=memberships.campaign response (JSON:API). Returns 128 // { status, cents } or null. 129 export function pickCampaignMembership(identity, campaignId) { 130 const inc = (identity && identity.included) || []; 131 for (const it of inc) { 132 if (it.type !== 'member') continue; 133 const camp = it.relationships && it.relationships.campaign && it.relationships.campaign.data; 134 if (!camp || String(camp.id) !== String(campaignId)) continue; 135 const a = it.attributes || {}; 136 return { status: a.patron_status || null, cents: a.currently_entitled_amount_cents || 0 }; 137 } 138 return null; 139 } 140 141 // Exchange a patron's auth code and read their membership of the owner's 142 // campaign. Returns { status, cents } or null. The patron token is used once 143 // and discarded here: nothing identifying is stored (design decision). 144 export async function verifyPatron(siteId, code, redirectUri, fetchImpl = fetch) { 145 const c = getOwnerConfig(siteId); 146 if (!c || !c.clientId || !c.clientSecret || !c.campaignId) return null; 147 const tokenRes = await fetchImpl(TOKEN_URL, { 148 method: 'POST', 149 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 150 body: new URLSearchParams({ 151 grant_type: 'authorization_code', code, 152 client_id: c.clientId, client_secret: c.clientSecret, redirect_uri: redirectUri, 153 }).toString(), 154 }); 155 if (!tokenRes.ok) return null; 156 const tok = await tokenRes.json(); 157 if (!tok || !tok.access_token) return null; 158 const url = 'https://www.patreon.com/api/oauth2/v2/identity' 159 + '?include=memberships.campaign' 160 + '&fields%5Bmember%5D=patron_status,currently_entitled_amount_cents'; 161 const idRes = await fetchImpl(url, { headers: { Authorization: `Bearer ${tok.access_token}` } }); 162 if (!idRes.ok) return null; 163 const identity = await idRes.json(); 164 return pickCampaignMembership(identity, c.campaignId); // token goes out of scope, discarded 165 } 166 126 167 function safeDecrypt(blob) { 127 168 try { return decrypt(blob); } catch { return null; } … … 131 172 getOwnerConfig, ownerStatus, saveOwnerConfig, disconnect, 132 173 defaultMinCents, needsRefresh, refreshCreatorToken, creatorAccessToken, 174 pickCampaignMembership, verifyPatron, 133 175 };
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)