7
7
"fmt"
8
8
"log"
9
9
"os"
10
+ "path/filepath"
10
11
"runtime"
11
12
"unsafe"
12
13
)
@@ -18,14 +19,42 @@ import (
18
19
#include <stdlib.h>
19
20
#include <stdint.h>
20
21
21
- // Define a function pointer type matching Rust's send_message
22
+ // Function pointer types matching Rust exports
22
23
typedef int32_t (*send_message_t)(
23
24
const uint8_t* msg_ptr,
24
25
size_t msg_len,
25
26
uint8_t** out_buf,
26
- size_t* out_len
27
+ size_t* out_len,
28
+ size_t* out_cap
27
29
);
28
30
31
+ typedef void (*free_message_t)(
32
+ uint8_t* buf,
33
+ size_t len,
34
+ size_t cap
35
+ );
36
+
37
+ // Trampoline wrappers so Go can call the function pointers
38
+ static inline int32_t call_send_message(
39
+ send_message_t fn,
40
+ const uint8_t* msg_ptr,
41
+ size_t msg_len,
42
+ uint8_t** out_buf,
43
+ size_t* out_len,
44
+ size_t* out_cap
45
+ ) {
46
+ return fn(msg_ptr, msg_len, out_buf, out_len, out_cap);
47
+ }
48
+
49
+ static inline void call_free_message(
50
+ free_message_t fn,
51
+ uint8_t* buf,
52
+ size_t len,
53
+ size_t cap
54
+ ) {
55
+ fn(buf, len, cap);
56
+ }
57
+
29
58
// dlopen wrapper
30
59
static void* open_library(const char* path) {
31
60
return dlopen(path, RTLD_NOW);
@@ -46,63 +75,77 @@ import "C"
46
75
type SharedLibCore struct {
47
76
handle unsafe.Pointer
48
77
sendMessage C.send_message_t
78
+ freeMessage C.free_message_t
49
79
}
50
80
51
- // Find1PasswordPath tries to return the default installation path of 1Password
52
- func find1PasswordPath () (string , error ) {
81
+ var coreLib * SharedLibCore
82
+
83
+ // find1PasswordLibPath returns the path to the 1Password shared library
84
+ // (libop_sdk_ipc_client.dylib/.so/.dll) depending on OS.
85
+ func find1PasswordLibPath () (string , error ) {
53
86
switch runtime .GOOS {
54
87
case "darwin" : // macOS
55
- // 1Password is typically installed as an app bundle
56
- paths := []string {
57
- "/Applications/1Password.app " ,
88
+ // Typical locations for the 1Password bundle
89
+ executables := []string {
90
+ "/Applications/1Password/Contents/MacOS/1Password " ,
58
91
}
59
- for _ , p := range paths {
60
- if _ , err := os .Stat (p ); err == nil {
61
- return p , nil
92
+
93
+ for _ , exe := range executables {
94
+ if _ , err := os .Stat (exe ); err == nil {
95
+ // Replace the executable name with the dylib name
96
+ libPath := filepath .Join (filepath .Dir (exe ), "libop_sdk_ipc_client.dylib" )
97
+ if _ , err := os .Stat (libPath ); err == nil {
98
+ return libPath , nil
99
+ }
62
100
}
63
101
}
64
102
65
103
case "linux" :
66
- // Linux installations vary
67
- paths := []string {
68
- "/var/lib/1password " ,
69
- "/opt/1Password " ,
104
+ // On Linux, it might live under /opt/1Password or similar
105
+ candidates := []string {
106
+ "/opt/1Password/libop_sdk_ipc_client.so " ,
107
+ "/usr/lib/1password/libop_sdk_ipc_client.so " ,
70
108
}
71
- for _ , p := range paths {
72
- if _ , err := os .Stat (p ); err == nil {
73
- return p , nil
109
+ for _ , lib := range candidates {
110
+ if _ , err := os .Stat (lib ); err == nil {
111
+ return lib , nil
74
112
}
75
113
}
76
114
77
115
case "windows" :
78
- // On Windows, 1Password installs under Program Files
79
- paths := []string {
116
+ // On Windows, shared libs are DLLs in the install directory
117
+ executables := []string {
80
118
`C:\Program Files\1Password\1Password.exe` ,
81
119
}
82
- for _ , p := range paths {
83
- if _ , err := os .Stat (p ); err == nil {
84
- return p , nil
120
+ for _ , exe := range executables {
121
+ if _ , err := os .Stat (exe ); err == nil {
122
+ libPath := filepath .Join (filepath .Dir (exe ), "op_sdk_ipc_client.dll" )
123
+ if _ , err := os .Stat (libPath ); err == nil {
124
+ return libPath , nil
125
+ }
85
126
}
86
127
}
87
128
}
88
129
89
- return "" , fmt .Errorf ("1Password not found" )
130
+ return "" , fmt .Errorf ("1Password desktop application not found" )
90
131
}
91
132
92
- func NewSharedLibCore () (* SharedLibCore , error ) {
93
- path , err := find1PasswordPath ()
94
- if err != nil {
95
- return nil , err
96
- }
97
- coreLib , err := LoadCore (path )
98
- if err != nil {
99
- return nil , err
133
+ func GetSharedLibCore () (* SharedLibCore , error ) {
134
+ if coreLib == nil {
135
+ path , err := find1PasswordLibPath ()
136
+ if err != nil {
137
+ return nil , err
138
+ }
139
+ coreLib , err = loadCore (path )
140
+ if err != nil {
141
+ return nil , err
142
+ }
100
143
}
101
144
102
145
return coreLib , nil
103
146
}
104
147
105
- func LoadCore (path string ) (* SharedLibCore , error ) {
148
+ func loadCore (path string ) (* SharedLibCore , error ) {
106
149
cPath := C .CString (path )
107
150
defer C .free (unsafe .Pointer (cPath ))
108
151
@@ -111,18 +154,28 @@ func LoadCore(path string) (*SharedLibCore, error) {
111
154
return nil , errors .New ("failed to open library" )
112
155
}
113
156
114
- symbol := C .CString ("send_message " )
157
+ symbol := C .CString ("op_sdk_ipc_send_message " )
115
158
defer C .free (unsafe .Pointer (symbol ))
116
159
117
- fn := C .load_symbol (handle , symbol )
118
- if fn == nil {
160
+ fnSend := C .load_symbol (handle , symbol )
161
+ if fnSend == nil {
119
162
C .close_library (handle )
120
163
return nil , errors .New ("failed to load send_message" )
121
164
}
122
165
166
+ symbolFree := C .CString ("op_sdk_ipc_free_response" )
167
+ defer C .free (unsafe .Pointer (symbolFree ))
168
+
169
+ fnFree := C .load_symbol (handle , symbolFree )
170
+ if fnFree == nil {
171
+ C .close_library (handle )
172
+ return nil , errors .New ("failed to load free_message" )
173
+ }
174
+
123
175
return & SharedLibCore {
124
176
handle : handle ,
125
- sendMessage : (C .send_message_t )(fn ),
177
+ sendMessage : (C .send_message_t )(fnSend ),
178
+ freeMessage : (C .free_message_t )(fnFree ),
126
179
}, nil
127
180
}
128
181
@@ -182,20 +235,24 @@ func (c *SharedLibCore) ReleaseClient(clientID uint64) {
182
235
func (c * SharedLibCore ) callSharedLibrary (input []byte ) ([]byte , error ) {
183
236
var outBuf * C.uint8_t
184
237
var outLen C.size_t
238
+ var outCap C.size_t
185
239
186
- retCode := c .sendMessage (
240
+ retCode := C .call_send_message (
241
+ c .sendMessage ,
187
242
(* C .uint8_t )(unsafe .Pointer (& input [0 ])),
188
243
C .size_t (len (input )),
189
244
& outBuf ,
190
245
& outLen ,
246
+ & outCap ,
191
247
)
192
248
193
249
if retCode != 0 {
194
250
return nil , fmt .Errorf ("send_message failed: %d" , int (retCode ))
195
251
}
196
252
197
253
resp := C .GoBytes (unsafe .Pointer (outBuf ), C .int (outLen ))
198
- C .free (unsafe .Pointer (outBuf ))
254
+ // Call trampoline with the function pointer
255
+ C .call_free_message (c .freeMessage , outBuf , outLen , outCap )
199
256
200
257
return resp , nil
201
258
}
0 commit comments