@visa/cli 2.1.1-rc.2 → 2.1.1-rc.4

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.
@@ -15,6 +15,24 @@ static NSString *kService = @"visa-cli";
15
15
  static NSString *kKeyAcct = @"attestation-key";
16
16
  static NSString *kTokenAcct = @"session-token";
17
17
 
18
+ static NSString *spkiPublicKeyB64(SecKeyRef key) {
19
+ SecKeyRef pubKey = SecKeyCopyPublicKey(key);
20
+ if (!pubKey) return nil;
21
+
22
+ CFErrorRef pubErr = NULL;
23
+ CFDataRef rawPub = SecKeyCopyExternalRepresentation(pubKey, &pubErr);
24
+ CFRelease(pubKey);
25
+ if (!rawPub) {
26
+ if (pubErr) CFRelease(pubErr);
27
+ return nil;
28
+ }
29
+
30
+ NSMutableData *spki = [NSMutableData dataWithBytes:SPKI_HEADER length:sizeof(SPKI_HEADER)];
31
+ [spki appendData:(__bridge NSData *)rawPub];
32
+ CFRelease(rawPub);
33
+ return [spki base64EncodedStringWithOptions:0];
34
+ }
35
+
18
36
  // ---------------------------------------------------------------------------
19
37
  // Keychain helpers for generic password items
20
38
  // ---------------------------------------------------------------------------
@@ -90,27 +108,59 @@ int cmd_generate_key(void) {
90
108
  NSString *privB64 = [(__bridge NSData *)rawPriv base64EncodedStringWithOptions:0];
91
109
  CFRelease(rawPriv);
92
110
 
93
- // Export public key in SPKI DER format
94
- SecKeyRef pubKey = SecKeyCopyPublicKey(privKey);
111
+ NSString *pubB64 = spkiPublicKeyB64(privKey);
95
112
  CFRelease(privKey);
96
- if (!pubKey) { printf("ERROR:Failed to get public key\n"); return 1; }
97
-
98
- CFErrorRef pubErr = NULL;
99
- CFDataRef rawPub = SecKeyCopyExternalRepresentation(pubKey, &pubErr);
100
- CFRelease(pubKey);
101
- if (!rawPub) {
102
- if (pubErr) CFRelease(pubErr);
113
+ if (!pubB64) {
103
114
  printf("ERROR:Failed to export public key\n");
104
115
  return 1;
105
116
  }
106
117
 
107
- NSMutableData *spki = [NSMutableData dataWithBytes:SPKI_HEADER length:sizeof(SPKI_HEADER)];
108
- [spki appendData:(__bridge NSData *)rawPub];
109
- CFRelease(rawPub);
110
-
111
118
  // Output both keys: OK:<private-b64>:<public-spki-b64>
112
- printf("OK:%s:%s\n", privB64.UTF8String,
113
- [spki base64EncodedStringWithOptions:0].UTF8String);
119
+ printf("OK:%s:%s\n", privB64.UTF8String, pubB64.UTF8String);
120
+ return 0;
121
+ }
122
+
123
+ int cmd_public_key(void) {
124
+ NSFileHandle *input = [NSFileHandle fileHandleWithStandardInput];
125
+ NSData *stdinData = [input readDataToEndOfFile];
126
+ NSString *keyB64 = [[NSString alloc] initWithData:stdinData encoding:NSUTF8StringEncoding];
127
+ keyB64 = [keyB64 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
128
+
129
+ if (!keyB64 || keyB64.length == 0) {
130
+ printf("ERROR:No key provided on stdin\n");
131
+ return 1;
132
+ }
133
+
134
+ NSData *rawKey = [[NSData alloc] initWithBase64EncodedString:keyB64 options:0];
135
+ if (!rawKey) {
136
+ printf("ERROR:Invalid base64 key data\n");
137
+ return 1;
138
+ }
139
+
140
+ NSDictionary *keyAttrs = @{
141
+ (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,
142
+ (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate,
143
+ (__bridge id)kSecAttrKeySizeInBits: @256,
144
+ };
145
+ CFErrorRef importErr = NULL;
146
+ SecKeyRef privKey = SecKeyCreateWithData(
147
+ (__bridge CFDataRef)rawKey,
148
+ (__bridge CFDictionaryRef)keyAttrs,
149
+ &importErr);
150
+ if (!privKey) {
151
+ if (importErr) CFRelease(importErr);
152
+ printf("ERROR:Failed to import key for public export\n");
153
+ return 1;
154
+ }
155
+
156
+ NSString *pubB64 = spkiPublicKeyB64(privKey);
157
+ CFRelease(privKey);
158
+ if (!pubB64) {
159
+ printf("ERROR:Failed to export public key\n");
160
+ return 1;
161
+ }
162
+
163
+ printf("OK:%s\n", pubB64.UTF8String);
114
164
  return 0;
115
165
  }
116
166
 
@@ -299,6 +349,7 @@ int main(int argc, const char *argv[]) {
299
349
  }
300
350
  const char *cmd = argv[1];
301
351
  if (strcmp(cmd, "generate-key") == 0) return cmd_generate_key();
352
+ else if (strcmp(cmd, "public-key") == 0) return cmd_public_key();
302
353
  else if (strcmp(cmd, "sign") == 0) {
303
354
  if (argc < 3) { fprintf(stderr, "Usage: visa-keychain sign <challenge> [reason]\n"); return 1; }
304
355
  return cmd_sign(argv[2], argc >= 4 ? argv[3] : NULL);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visa/cli",
3
- "version": "2.1.1-rc.2",
3
+ "version": "2.1.1-rc.4",
4
4
  "description": "AI-powered payments for Claude Code",
5
5
  "bin": {
6
6
  "visa-cli": "./bin/visa-cli.js"
package/server.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
3
3
  "name": "io.github.visa-crypto-labs/visa-cli",
4
- "version": "2.1.1-rc.2",
4
+ "version": "2.1.1-rc.4",
5
5
  "title": "Visa CLI",
6
6
  "description": "AI-powered payments and creative tools for coding agents. Generate images, music, video, query crypto prices, and make purchases — all from your AI coding assistant.",
7
7
  "websiteUrl": "https://github.com/Visa-Crypto-Labs/Visa-mono/tree/main/packages/cli#readme",
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "registryType": "npm",
11
11
  "identifier": "@visa/cli",
12
- "version": "2.1.1-rc.2",
12
+ "version": "2.1.1-rc.4",
13
13
  "transport": {
14
14
  "type": "stdio"
15
15
  },