@@ -32,33 +32,33 @@ import (
3232 "github.com/hyperledger/firefly-common/pkg/i18n"
3333 "github.com/hyperledger/firefly-common/pkg/log"
3434 "github.com/hyperledger/firefly-signer/internal/signermsgs"
35- "github.com/hyperledger/firefly-signer/pkg/eip712"
36- "github.com/hyperledger/firefly-signer/pkg/ethsigner"
37- "github.com/hyperledger/firefly-signer/pkg/ethtypes"
3835 "github.com/hyperledger/firefly-signer/pkg/keystorev3"
39- "github.com/hyperledger/firefly-signer/pkg/secp256k1"
4036 "github.com/karlseguin/ccache"
4137 "github.com/pelletier/go-toml"
4238 "gopkg.in/yaml.v2"
4339)
4440
45- type SyncAddressCallback func (context.Context , ethtypes. Address0xHex ) error
41+ type SyncCallback func (context.Context , string ) error
4642
4743// Wallet is a directory containing a set of KeystoreV3 files, conforming
4844// to the ethsigner.Wallet interface and providing notifications when new
4945// keys are added to the wallet (via FS listener).
50- type Wallet interface {
51- ethsigner.WalletTypedData
52- GetWalletFile (ctx context.Context , addr ethtypes.Address0xHex ) (keystorev3.WalletFile , error )
53- SetSyncAddressCallback (SyncAddressCallback )
54- AddListener (listener chan <- ethtypes.Address0xHex )
46+ type WalletGeneric interface {
47+ Initialize (ctx context.Context ) error
48+ Refresh (ctx context.Context ) error
49+ Close () error
50+
51+ GetAccounts (ctx context.Context ) ([]string , error )
52+ GetWalletFile (ctx context.Context , addr string ) (keystorev3.WalletFile , error )
53+ SetSyncCallback (SyncCallback )
54+ AddListener (listener chan <- string )
5555}
5656
57- func NewFilesystemWallet (ctx context.Context , conf * Config , initialListeners ... chan <- ethtypes. Address0xHex ) (ww Wallet , err error ) {
57+ func NewFilesystemWalletGeneric (ctx context.Context , conf * ConfigGeneric , initialListeners ... chan <- string ) (ww WalletGeneric , err error ) {
5858 w := & fsWallet {
5959 conf : * conf ,
6060 listeners : initialListeners ,
61- addressToFileMap : make (map [ethtypes. Address0xHex ]string ),
61+ addressToFileMap : make (map [string ]string ),
6262 }
6363 w .signerCache = ccache .New (
6464 // We use a LRU cache with a size-aware max
@@ -96,39 +96,23 @@ func goTemplateFromConfig(ctx context.Context, name string, templateStr string)
9696}
9797
9898type fsWallet struct {
99- conf Config
99+ conf ConfigGeneric
100100 signerCache * ccache.Cache
101101 signerCacheTTL time.Duration
102102 metadataKeyFileProperty * template.Template
103103 metadataPasswordFileProperty * template.Template
104104 primaryMatchRegex * regexp.Regexp
105- syncAddressCallback SyncAddressCallback
105+ syncCallback SyncCallback
106106
107107 mux sync.Mutex
108- addressToFileMap map [ethtypes. Address0xHex ]string // map for lookup to filename
109- addressList []* ethtypes. Address0xHex // ordered list in filename at startup, then notification order
110- listeners []chan <- ethtypes. Address0xHex
108+ addressToFileMap map [string ]string // map for lookup to filename
109+ addressList []string // ordered list in filename at startup, then notification order
110+ listeners []chan <- string
111111 fsListenerCancel context.CancelFunc
112112 fsListenerStarted chan error
113113 fsListenerDone chan struct {}
114114}
115115
116- func (w * fsWallet ) Sign (ctx context.Context , txn * ethsigner.Transaction , chainID int64 ) ([]byte , error ) {
117- keypair , err := w .getSignerForJSONAccount (ctx , txn .From )
118- if err != nil {
119- return nil , err
120- }
121- return txn .Sign (keypair , chainID )
122- }
123-
124- func (w * fsWallet ) SignTypedDataV4 (ctx context.Context , from ethtypes.Address0xHex , payload * eip712.TypedData ) (* ethsigner.EIP712Result , error ) {
125- keypair , err := w .getSignerForAddr (ctx , from )
126- if err != nil {
127- return nil , err
128- }
129- return ethsigner .SignTypedDataV4 (ctx , keypair , payload )
130- }
131-
132116func (w * fsWallet ) Initialize (ctx context.Context ) error {
133117 // Run a get accounts pass, to check all is ok
134118 lCtx , lCancel := context .WithCancel (log .WithLogField (ctx , "fswallet" , w .conf .Path ))
@@ -144,7 +128,7 @@ func (w *fsWallet) Initialize(ctx context.Context) error {
144128}
145129
146130// Asynchronously listen for all addresses as they are detected - during startup, or after startup
147- func (w * fsWallet ) AddListener (listener chan <- ethtypes. Address0xHex ) {
131+ func (w * fsWallet ) AddListener (listener chan <- string ) {
148132 w .mux .Lock ()
149133 defer w .mux .Unlock ()
150134 w .listeners = append (w .listeners , listener )
@@ -162,47 +146,54 @@ func (w *fsWallet) AddListener(listener chan<- ethtypes.Address0xHex) {
162146// will be called concurrently. However, it is guaranteed to be called in-line with the
163147// initialize/refresh so you know once that calls returns all new keys detected by it have
164148// driven the callback.
165- func (w * fsWallet ) SetSyncAddressCallback (callback SyncAddressCallback ) {
166- w .syncAddressCallback = callback
149+ func (w * fsWallet ) SetSyncCallback (callback SyncCallback ) {
150+ w .syncCallback = callback
167151}
168152
169153// GetAccounts returns the currently cached list of known addresses
170- func (w * fsWallet ) GetAccounts (_ context.Context ) ([]* ethtypes. Address0xHex , error ) {
154+ func (w * fsWallet ) GetAccounts (_ context.Context ) ([]string , error ) {
171155 w .mux .Lock ()
172156 defer w .mux .Unlock ()
173- accounts := make ([]* ethtypes. Address0xHex , len (w .addressList ))
157+ accounts := make ([]string , len (w .addressList ))
174158 copy (accounts , w .addressList )
175159 return accounts , nil
176160}
177161
178- func (w * fsWallet ) matchFilename (ctx context.Context , f fs.FileInfo ) * ethtypes. Address0xHex {
162+ func (w * fsWallet ) matchFilename (ctx context.Context , f fs.FileInfo ) string {
179163 if f .IsDir () {
180164 log .L (ctx ).Tracef ("Ignoring '%s/%s: directory" , w .conf .Path , f .Name ())
181- return nil
165+ return ""
182166 }
183167 if w .primaryMatchRegex != nil {
184168 match := w .primaryMatchRegex .FindStringSubmatch (f .Name ())
185169 if match == nil {
186170 log .L (ctx ).Tracef ("Ignoring '%s/%s': does not match regexp" , w .conf .Path , f .Name ())
187- return nil
171+ return ""
188172 }
189- addr , err := ethtypes .NewAddress (match [1 ]) // safe due to SubexpNames() length check
190- if err != nil {
191- log .L (ctx ).Warnf ("Ignoring '%s/%s': invalid address '%s': %s" , w .conf .Path , f .Name (), match [1 ], err )
192- return nil
173+ var err error
174+ addrString := match [1 ]
175+ if w .conf .AddressValidator != nil {
176+ addrString , err = w .conf .AddressValidator (ctx , addrString )
177+ if err != nil {
178+ log .L (ctx ).Warnf ("Ignoring '%s/%s': invalid address '%s': %s" , w .conf .Path , f .Name (), match [1 ], err )
179+ return ""
180+ }
193181 }
194- return addr
182+ return addrString
195183 }
196184 if ! strings .HasSuffix (f .Name (), w .conf .Filenames .PrimaryExt ) {
197185 log .L (ctx ).Tracef ("Ignoring '%s/%s: does not match extension '%s'" , w .conf .Path , f .Name (), w .conf .Filenames .PrimaryExt )
198186 }
199187 addrString := strings .TrimSuffix (f .Name (), w .conf .Filenames .PrimaryExt )
200- addr , err := ethtypes .NewAddress (addrString )
201- if err != nil {
202- log .L (ctx ).Warnf ("Ignoring '%s/%s': invalid address '%s': %s" , w .conf .Path , f .Name (), addrString , err )
203- return nil
188+ if w .conf .AddressValidator != nil {
189+ var err error
190+ addrString , err = w .conf .AddressValidator (ctx , addrString )
191+ if err != nil {
192+ log .L (ctx ).Warnf ("Ignoring '%s/%s': invalid address '%s': %s" , w .conf .Path , f .Name (), addrString , err )
193+ return ""
194+ }
204195 }
205- return addr
196+ return addrString
206197}
207198
208199func (w * fsWallet ) Refresh (ctx context.Context ) error {
@@ -221,16 +212,16 @@ func (w *fsWallet) Refresh(ctx context.Context) error {
221212 return w .notifyNewFiles (ctx , files ... )
222213}
223214
224- func (w * fsWallet ) processNewFiles (ctx context.Context , files ... fs.FileInfo ) (listeners []chan <- ethtypes. Address0xHex , newAddresses []* ethtypes. Address0xHex ) {
215+ func (w * fsWallet ) processNewFiles (ctx context.Context , files ... fs.FileInfo ) (listeners []chan <- string , newAddresses []string ) {
225216 // Lock now we have the list
226217 w .mux .Lock ()
227218 defer w .mux .Unlock ()
228- newAddresses = make ([]* ethtypes. Address0xHex , 0 )
219+ newAddresses = make ([]string , 0 )
229220 for _ , f := range files {
230221 addr := w .matchFilename (ctx , f )
231- if addr != nil {
232- if existingFilename , exists := w .addressToFileMap [* addr ]; existingFilename != f .Name () {
233- w .addressToFileMap [* addr ] = f .Name ()
222+ if addr != "" {
223+ if existingFilename , exists := w .addressToFileMap [addr ]; existingFilename != f .Name () {
224+ w .addressToFileMap [addr ] = f .Name ()
234225 if ! exists {
235226 log .L (ctx ).Debugf ("Added address: %s (file=%s)" , addr , f .Name ())
236227 w .addressList = append (w .addressList , addr )
@@ -239,7 +230,7 @@ func (w *fsWallet) processNewFiles(ctx context.Context, files ...fs.FileInfo) (l
239230 }
240231 }
241232 }
242- listeners = make ([]chan <- ethtypes. Address0xHex , len (w .listeners ))
233+ listeners = make ([]chan <- string , len (w .listeners ))
243234 copy (listeners , w .listeners )
244235 log .L (ctx ).Debugf ("Processed %d files. Found %d new addresses" , len (files ), len (newAddresses ))
245236 return listeners , newAddresses
@@ -252,10 +243,10 @@ func (w *fsWallet) notifyNewFiles(ctx context.Context, files ...fs.FileInfo) err
252243
253244 if len (newAddresses ) > 0 {
254245
255- if w .syncAddressCallback != nil {
246+ if w .syncCallback != nil {
256247 // Sync callbacks are called here in-line, but outside the lock.
257248 for _ , addr := range newAddresses {
258- if err := w .syncAddressCallback (ctx , * addr ); err != nil {
249+ if err := w .syncCallback (ctx , addr ); err != nil {
259250 log .L (ctx ).Errorf ("sync listener returned error for address %s: %s" , addr , err )
260251 return err
261252 }
@@ -267,7 +258,7 @@ func (w *fsWallet) notifyNewFiles(ctx context.Context, files ...fs.FileInfo) err
267258 go func () {
268259 for _ , l := range listeners {
269260 for _ , addr := range newAddresses {
270- l <- * addr
261+ l <- addr
271262 }
272263 }
273264 }()
@@ -286,59 +277,37 @@ func (w *fsWallet) Close() error {
286277 return nil
287278}
288279
289- func (w * fsWallet ) getSignerForJSONAccount (ctx context.Context , rawAddrJSON json. RawMessage ) (* secp256k1. KeyPair , error ) {
280+ func (w * fsWallet ) GetWalletFile (ctx context.Context , addrString string ) (keystorev3. WalletFile , error ) {
290281
291- // We require an ethereum address in the "from" field
292- var from ethtypes.Address0xHex
293- err := json .Unmarshal (rawAddrJSON , & from )
294- if err != nil {
295- return nil , err
296- }
297- return w .getSignerForAddr (ctx , from )
298- }
299-
300- func (w * fsWallet ) getSignerForAddr (ctx context.Context , from ethtypes.Address0xHex ) (* secp256k1.KeyPair , error ) {
301-
302- wf , err := w .GetWalletFile (ctx , from )
303- if err != nil {
304- return nil , err
305- }
306- return wf .KeyPair (), nil
307-
308- }
309-
310- func (w * fsWallet ) GetWalletFile (ctx context.Context , addr ethtypes.Address0xHex ) (keystorev3.WalletFile , error ) {
311-
312- addrString := addr .String ()
313282 cached := w .signerCache .Get (addrString )
314283 if cached != nil {
315284 cached .Extend (w .signerCacheTTL )
316285 return cached .Value ().(keystorev3.WalletFile ), nil
317286 }
318287
319288 w .mux .Lock ()
320- primaryFilename , ok := w .addressToFileMap [addr ]
289+ primaryFilename , ok := w .addressToFileMap [addrString ]
321290 w .mux .Unlock ()
322291 if ! ok {
323- return nil , i18n .NewError (ctx , signermsgs .MsgWalletNotAvailable , addr )
292+ return nil , i18n .NewError (ctx , signermsgs .MsgWalletNotAvailable , addrString )
324293 }
325294
326- kv3 , err := w .loadWalletFile (ctx , addr , path .Join (w .conf .Path , primaryFilename ))
295+ kv3 , err := w .loadWalletFile (ctx , addrString , path .Join (w .conf .Path , primaryFilename ))
327296 if err != nil {
328297 return nil , err
329298 }
330299
331- keypair := kv3 .KeyPair ()
332- if keypair .Address != addr {
333- return nil , i18n .NewError (ctx , signermsgs .MsgAddressMismatch , keypair .Address , addr )
300+ if w .conf .WalletFileValidator != nil {
301+ if err := w .conf .WalletFileValidator (ctx , addrString , kv3 ); err != nil {
302+ return nil , err
303+ }
334304 }
335305
336306 w .signerCache .Set (addrString , kv3 , w .signerCacheTTL )
337307 return kv3 , err
338-
339308}
340309
341- func (w * fsWallet ) loadWalletFile (ctx context.Context , addr ethtypes. Address0xHex , primaryFilename string ) (keystorev3.WalletFile , error ) {
310+ func (w * fsWallet ) loadWalletFile (ctx context.Context , addr string , primaryFilename string ) (keystorev3.WalletFile , error ) {
342311
343312 b , err := os .ReadFile (primaryFilename )
344313 if err != nil {
@@ -395,7 +364,7 @@ func (w *fsWallet) loadWalletFile(ctx context.Context, addr ethtypes.Address0xHe
395364
396365}
397366
398- func (w * fsWallet ) getKeyAndPasswordFiles (ctx context.Context , addr ethtypes. Address0xHex , primaryFilename string , primaryFile []byte ) (kf string , pf string , err error ) {
367+ func (w * fsWallet ) getKeyAndPasswordFiles (ctx context.Context , addr string , primaryFilename string , primaryFile []byte ) (kf string , pf string , err error ) {
399368 if strings .ToLower (w .conf .Metadata .Format ) == "auto" {
400369 w .conf .Metadata .Format = strings .TrimPrefix (w .conf .Filenames .PrimaryExt , "." )
401370 }
@@ -414,7 +383,7 @@ func (w *fsWallet) getKeyAndPasswordFiles(ctx context.Context, addr ethtypes.Add
414383 if passwordPath == "" {
415384 passwordPath = w .conf .Path
416385 }
417- passwordFilename := addr . String ()
386+ passwordFilename := addr
418387 if ! w .conf .Filenames .With0xPrefix {
419388 passwordFilename = strings .TrimPrefix (passwordFilename , "0x" )
420389 }
0 commit comments