@askalf/dario 3.9.0 → 3.9.1
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.
- package/dist/oauth.js +69 -1
- package/package.json +1 -1
package/dist/oauth.js
CHANGED
|
@@ -52,8 +52,47 @@ function getClaudeCodeCredentialsPath() {
|
|
|
52
52
|
* store instead of ~/.claude/.credentials.json:
|
|
53
53
|
* - macOS: Keychain, service "Claude Code-credentials"
|
|
54
54
|
* - Linux: libsecret / Secret Service D-Bus API via `secret-tool`
|
|
55
|
-
* - Windows: Windows Credential Manager via
|
|
55
|
+
* - Windows: Windows Credential Manager via PowerShell + Win32 CredEnumerate
|
|
56
56
|
*/
|
|
57
|
+
const WIN_CRED_SCRIPT = `
|
|
58
|
+
$ErrorActionPreference = 'Stop'
|
|
59
|
+
$sig = @"
|
|
60
|
+
using System;
|
|
61
|
+
using System.Runtime.InteropServices;
|
|
62
|
+
public class CM {
|
|
63
|
+
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
|
64
|
+
public struct CRED {
|
|
65
|
+
public uint Flags; public uint Type; public string TargetName;
|
|
66
|
+
public string Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LW;
|
|
67
|
+
public uint BlobSize; public IntPtr Blob;
|
|
68
|
+
public uint Persist; public uint AC; public IntPtr Attrs;
|
|
69
|
+
public string Alias; public string UN;
|
|
70
|
+
}
|
|
71
|
+
[DllImport("advapi32.dll", EntryPoint="CredEnumerateW", CharSet=CharSet.Unicode, SetLastError=true)]
|
|
72
|
+
public static extern bool CredEnumerate(string filter, uint flag, out uint count, out IntPtr pCredentials);
|
|
73
|
+
[DllImport("advapi32.dll", EntryPoint="CredFree")]
|
|
74
|
+
public static extern void CredFree(IntPtr cred);
|
|
75
|
+
}
|
|
76
|
+
"@
|
|
77
|
+
Add-Type -TypeDefinition $sig
|
|
78
|
+
$count = 0
|
|
79
|
+
$ptr = [IntPtr]::Zero
|
|
80
|
+
if ([CM]::CredEnumerate('Claude Code-credentials*', 0, [ref]$count, [ref]$ptr)) {
|
|
81
|
+
try {
|
|
82
|
+
for ($i = 0; $i -lt $count; $i++) {
|
|
83
|
+
$credPtr = [System.Runtime.InteropServices.Marshal]::ReadIntPtr($ptr, $i * [IntPtr]::Size)
|
|
84
|
+
$cred = [System.Runtime.InteropServices.Marshal]::PtrToStructure($credPtr, [type][CM+CRED])
|
|
85
|
+
if ($cred.BlobSize -gt 0) {
|
|
86
|
+
$bytes = New-Object byte[] $cred.BlobSize
|
|
87
|
+
[System.Runtime.InteropServices.Marshal]::Copy($cred.Blob, $bytes, 0, $cred.BlobSize)
|
|
88
|
+
Write-Output ([System.Text.Encoding]::Unicode.GetString($bytes))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} finally {
|
|
92
|
+
[CM]::CredFree($ptr)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
57
96
|
async function loadKeychainCredentials() {
|
|
58
97
|
try {
|
|
59
98
|
if (platform() === 'darwin') {
|
|
@@ -74,6 +113,35 @@ async function loadKeychainCredentials() {
|
|
|
74
113
|
return parsed;
|
|
75
114
|
}
|
|
76
115
|
}
|
|
116
|
+
else if (platform() === 'win32') {
|
|
117
|
+
// Windows Credential Manager via PowerShell + Win32 CredEnumerate.
|
|
118
|
+
// Claude Code on Windows (via Node keytar) stores OAuth tokens as
|
|
119
|
+
// Generic credentials with target prefix "Claude Code-credentials".
|
|
120
|
+
// We enumerate matching credentials and return the first one that
|
|
121
|
+
// parses as a valid CC credentials blob. The password field is
|
|
122
|
+
// stored as UTF-16LE bytes (keytar convention on Windows).
|
|
123
|
+
//
|
|
124
|
+
// PowerShell CredEnumerate sets LastWin32Error=1168 (ERROR_NOT_FOUND)
|
|
125
|
+
// when the filter matches nothing — we catch the non-zero exit and
|
|
126
|
+
// return null so the caller falls back to the file-path checks.
|
|
127
|
+
const raw = await new Promise((resolve, reject) => {
|
|
128
|
+
execFile('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', WIN_CRED_SCRIPT], { timeout: 5000, windowsHide: true }, (err, stdout) => (err ? reject(err) : resolve(stdout)));
|
|
129
|
+
});
|
|
130
|
+
// Script emits one JSON blob per matching credential, newline-separated.
|
|
131
|
+
// Return the first one that parses with the expected CC shape.
|
|
132
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
133
|
+
const s = line.trim();
|
|
134
|
+
if (!s)
|
|
135
|
+
continue;
|
|
136
|
+
try {
|
|
137
|
+
const parsed = JSON.parse(s);
|
|
138
|
+
if (parsed?.claudeAiOauth?.accessToken && parsed?.claudeAiOauth?.refreshToken) {
|
|
139
|
+
return parsed;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch { /* not a valid JSON credential blob — try next */ }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
77
145
|
}
|
|
78
146
|
catch { /* keychain not available or no entry */ }
|
|
79
147
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.1",
|
|
4
4
|
"description": "A local LLM router. One endpoint, every provider — Claude subscriptions, OpenAI, OpenRouter, Groq, local LiteLLM, any OpenAI-compat endpoint — your tools don't need to change.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|