@makolabs/ripple 1.6.6 → 1.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -88,43 +88,56 @@ async function makeAuthRequest(endpoint, options = {}) {
|
|
|
88
88
|
...options.headers
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
|
-
const
|
|
92
|
-
|
|
91
|
+
const text = await response.text();
|
|
92
|
+
let data;
|
|
93
|
+
try {
|
|
94
|
+
data = JSON.parse(text);
|
|
95
|
+
}
|
|
96
|
+
catch (parseError) {
|
|
97
|
+
// Not JSON, treat as plain text error (e.g., "404 page not found")
|
|
98
|
+
data = { error: text, message: text };
|
|
99
|
+
}
|
|
93
100
|
return {
|
|
94
101
|
ok: response.ok,
|
|
95
102
|
status: response.status,
|
|
96
|
-
data:
|
|
103
|
+
data: data
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
async function verifyApiKeyToken(apiKey) {
|
|
100
107
|
try {
|
|
101
|
-
const result = await makeAuthRequest('/auth/
|
|
108
|
+
const result = await makeAuthRequest('/auth/token', {
|
|
102
109
|
method: 'POST',
|
|
103
110
|
headers: {
|
|
104
111
|
'X-API-Key': apiKey
|
|
105
112
|
}
|
|
106
113
|
});
|
|
107
114
|
if (result.ok && result.data?.data?.access_token) {
|
|
108
|
-
|
|
115
|
+
const token = result.data.data.access_token;
|
|
109
116
|
const verifyResult = await makeAuthRequest('/auth/verify', {
|
|
110
|
-
method: '
|
|
117
|
+
method: 'GET',
|
|
111
118
|
headers: {
|
|
112
|
-
'Authorization': `Bearer ${
|
|
119
|
+
'Authorization': `Bearer ${token}`
|
|
113
120
|
}
|
|
114
121
|
});
|
|
115
122
|
if (verifyResult.ok && verifyResult.data?.data) {
|
|
123
|
+
// The API returns "scope" (singular) as a space-separated string, not "scopes" array
|
|
124
|
+
const scopeString = verifyResult.data.data.scope;
|
|
125
|
+
const scopes = scopeString ? scopeString.split(' ').filter(Boolean) : [];
|
|
116
126
|
return {
|
|
117
127
|
valid: true,
|
|
118
|
-
scopes:
|
|
128
|
+
scopes: scopes
|
|
119
129
|
};
|
|
120
130
|
}
|
|
121
131
|
}
|
|
132
|
+
const errorMsg = result.data?.message || result.data?.error || `API key verification failed with status ${result.status}`;
|
|
133
|
+
console.warn('[verifyApiKeyToken] Verification failed:', errorMsg);
|
|
122
134
|
return {
|
|
123
135
|
valid: false,
|
|
124
|
-
error:
|
|
136
|
+
error: errorMsg
|
|
125
137
|
};
|
|
126
138
|
}
|
|
127
139
|
catch (error) {
|
|
140
|
+
console.error('[verifyApiKeyToken] Exception during verification:', error);
|
|
128
141
|
return {
|
|
129
142
|
valid: false,
|
|
130
143
|
error: error instanceof Error ? error.message : 'Unknown error during verification'
|
|
@@ -444,12 +457,12 @@ export const updateUserPermissions = command('unchecked', async (options) => {
|
|
|
444
457
|
if (apiKeyString) {
|
|
445
458
|
try {
|
|
446
459
|
const verification = await verifyApiKeyToken(apiKeyString);
|
|
460
|
+
console.log('[updateUserPermissions] Key verification:', verification);
|
|
447
461
|
if (verification.valid) {
|
|
448
|
-
console.log('[updateUserPermissions] Token verification successful. Scopes:', verification.scopes);
|
|
449
462
|
// Check if the scopes match what we expect
|
|
450
463
|
const scopesMatch = filteredPermissions.every(perm => verification.scopes?.includes(perm));
|
|
451
464
|
if (!scopesMatch) {
|
|
452
|
-
console.warn('[updateUserPermissions]
|
|
465
|
+
console.warn('[updateUserPermissions] Scopes mismatch. Expected:', filteredPermissions, 'Got:', verification.scopes);
|
|
453
466
|
}
|
|
454
467
|
}
|
|
455
468
|
else {
|
|
@@ -490,12 +503,14 @@ export const generateApiKey = command('unchecked', async (options) => {
|
|
|
490
503
|
const userKeys = (allKeysData?.data?.data || []).filter((key) => key.status === 'active');
|
|
491
504
|
let newApiKey;
|
|
492
505
|
let wasRotated = false;
|
|
506
|
+
let oldApiKey;
|
|
507
|
+
let currentUser = null;
|
|
493
508
|
if (userKeys.length > 0 && options.revokeOld) {
|
|
494
509
|
// Use rotate endpoint (per Mako Auth API spec)
|
|
495
510
|
const keyId = userKeys[0].id;
|
|
496
|
-
// Get the old API key
|
|
497
|
-
|
|
498
|
-
|
|
511
|
+
// Get the old API key from Clerk's private_metadata
|
|
512
|
+
currentUser = await makeClerkRequest(`/users/${options.userId}`);
|
|
513
|
+
oldApiKey = currentUser.private_metadata?.mako_api_key;
|
|
499
514
|
const rotateResult = await makeAdminRequest(`/admin/keys/${keyId}/rotate`, {
|
|
500
515
|
method: 'POST',
|
|
501
516
|
body: JSON.stringify({
|
|
@@ -512,11 +527,9 @@ export const generateApiKey = command('unchecked', async (options) => {
|
|
|
512
527
|
if (oldApiKey) {
|
|
513
528
|
try {
|
|
514
529
|
const oldKeyVerification = await verifyApiKeyToken(oldApiKey);
|
|
530
|
+
console.log('[generateApiKey] Old key verification:', oldKeyVerification.valid ? 'Still valid ⚠️' : 'Revoked ✓');
|
|
515
531
|
if (oldKeyVerification.valid) {
|
|
516
|
-
console.warn('[generateApiKey] Old API key
|
|
517
|
-
}
|
|
518
|
-
else {
|
|
519
|
-
console.log('[generateApiKey] Old API key successfully revoked');
|
|
532
|
+
console.warn('[generateApiKey] Old API key still valid after rotation');
|
|
520
533
|
}
|
|
521
534
|
}
|
|
522
535
|
catch (verifyError) {
|
|
@@ -526,16 +539,16 @@ export const generateApiKey = command('unchecked', async (options) => {
|
|
|
526
539
|
// Verify new key works with correct scopes
|
|
527
540
|
try {
|
|
528
541
|
const newKeyVerification = await verifyApiKeyToken(newApiKey);
|
|
542
|
+
console.log('[generateApiKey] New key verification:', newKeyVerification);
|
|
529
543
|
if (newKeyVerification.valid) {
|
|
530
|
-
console.log('[generateApiKey] New API key verification successful. Scopes:', newKeyVerification.scopes);
|
|
531
544
|
// Check if the scopes match what we expect
|
|
532
545
|
const scopesMatch = filteredPermissions.every(perm => newKeyVerification.scopes?.includes(perm));
|
|
533
546
|
if (!scopesMatch) {
|
|
534
|
-
console.warn('[generateApiKey]
|
|
547
|
+
console.warn('[generateApiKey] Scopes mismatch. Expected:', filteredPermissions, 'Got:', newKeyVerification.scopes);
|
|
535
548
|
}
|
|
536
549
|
}
|
|
537
550
|
else {
|
|
538
|
-
console.warn('[generateApiKey] New
|
|
551
|
+
console.warn('[generateApiKey] New key verification failed:', newKeyVerification.error);
|
|
539
552
|
}
|
|
540
553
|
}
|
|
541
554
|
catch (verifyError) {
|
|
@@ -555,7 +568,10 @@ export const generateApiKey = command('unchecked', async (options) => {
|
|
|
555
568
|
}
|
|
556
569
|
// Update Clerk profile with new key
|
|
557
570
|
try {
|
|
558
|
-
|
|
571
|
+
// Reuse currentUser if already fetched (during rotation), otherwise fetch it
|
|
572
|
+
if (!currentUser) {
|
|
573
|
+
currentUser = await makeClerkRequest(`/users/${options.userId}`);
|
|
574
|
+
}
|
|
559
575
|
await makeClerkRequest(`/users/${options.userId}`, {
|
|
560
576
|
method: 'PATCH',
|
|
561
577
|
body: JSON.stringify({
|
|
@@ -589,24 +605,39 @@ export const verifyToken = command('unchecked', async (options) => {
|
|
|
589
605
|
const result = await verifyApiKeyToken(options.apiKey);
|
|
590
606
|
// Also return the issued token for debugging
|
|
591
607
|
if (result.valid) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
608
|
+
try {
|
|
609
|
+
const tokenResult = await makeAuthRequest('/auth/token', {
|
|
610
|
+
method: 'POST',
|
|
611
|
+
headers: {
|
|
612
|
+
'X-API-Key': options.apiKey
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
const finalResult = {
|
|
616
|
+
valid: result.valid,
|
|
617
|
+
scopes: result.scopes,
|
|
618
|
+
token: tokenResult.data?.data?.access_token
|
|
619
|
+
};
|
|
620
|
+
// Ensure result is serializable
|
|
621
|
+
return JSON.parse(JSON.stringify(finalResult));
|
|
622
|
+
}
|
|
623
|
+
catch (tokenError) {
|
|
624
|
+
console.warn('[verifyToken] Could not fetch token:', tokenError);
|
|
625
|
+
// Return result without token
|
|
626
|
+
return JSON.parse(JSON.stringify({
|
|
627
|
+
valid: result.valid,
|
|
628
|
+
scopes: result.scopes
|
|
629
|
+
}));
|
|
630
|
+
}
|
|
602
631
|
}
|
|
603
|
-
|
|
632
|
+
// Ensure result is serializable
|
|
633
|
+
return JSON.parse(JSON.stringify(result));
|
|
604
634
|
}
|
|
605
635
|
catch (error) {
|
|
606
636
|
console.error('[verifyToken] Error:', error);
|
|
607
|
-
|
|
637
|
+
const errorResult = {
|
|
608
638
|
valid: false,
|
|
609
639
|
error: error instanceof Error ? error.message : 'Unknown error during verification'
|
|
610
640
|
};
|
|
641
|
+
return JSON.parse(JSON.stringify(errorResult));
|
|
611
642
|
}
|
|
612
643
|
});
|