@@ -59,6 +59,17 @@ type Client struct {
5959
6060 // Enable Debug Logging
6161 Debug bool
62+
63+ // Cache for resource types (rarely change)
64+ resourceTypesCache []ResourceType
65+
66+ // Cache for metadata keys (includes decrypted private keys)
67+ metadataKeysCache []MetadataKey
68+ // Cache for decrypted metadata private keys, keyed by metadata key ID
69+ decryptedMetadataKeysCache map [string ]* crypto.Key
70+
71+ // Cache for session keys used for metadata decryption, keyed by metadata key ID
72+ sessionKeyCache map [string ]* crypto.SessionKey
6273}
6374
6475// PublicKeyReponse the Body of a Public Key Api Request
@@ -98,11 +109,13 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User
98109
99110 // Create Client Object
100111 c := & Client {
101- httpClient : httpClient ,
102- baseURL : u ,
103- userAgent : UserAgent ,
104- userPrivateKey : unlockedKey ,
105- pgp : pgp ,
112+ httpClient : httpClient ,
113+ baseURL : u ,
114+ userAgent : UserAgent ,
115+ userPrivateKey : unlockedKey ,
116+ pgp : pgp ,
117+ decryptedMetadataKeysCache : make (map [string ]* crypto.Key ),
118+ sessionKeyCache : make (map [string ]* crypto.SessionKey ),
106119 }
107120 return c , err
108121}
@@ -277,3 +290,176 @@ func (c *Client) GetPGPHandle() *crypto.PGPHandle {
277290func (c * Client ) GetPasswordExpirySettings () PasswordExpirySettings {
278291 return c .passwordExpirySettings
279292}
293+
294+ // ClearCache clears all cached data
295+ func (c * Client ) ClearCache () {
296+ c .ClearResourceTypesCache ()
297+ c .ClearMetadataKeysCache ()
298+ c .ClearSessionKeyCache ()
299+ }
300+
301+ // ClearResourceTypesCache clears the resource types cache
302+ func (c * Client ) ClearResourceTypesCache () {
303+ c .resourceTypesCache = nil
304+ }
305+
306+ // ClearMetadataKeysCache clears the metadata keys cache
307+ func (c * Client ) ClearMetadataKeysCache () {
308+ c .metadataKeysCache = nil
309+ c .decryptedMetadataKeysCache = make (map [string ]* crypto.Key )
310+ }
311+
312+ // ClearSessionKeyCache clears the session key cache used for metadata decryption
313+ func (c * Client ) ClearSessionKeyCache () {
314+ c .sessionKeyCache = make (map [string ]* crypto.SessionKey )
315+ }
316+
317+ // GetResourceTypesCached returns cached resource types, fetching from API if cache is empty
318+ func (c * Client ) GetResourceTypesCached (ctx context.Context ) ([]ResourceType , error ) {
319+ if c .resourceTypesCache != nil {
320+ return c .resourceTypesCache , nil
321+ }
322+
323+ types , err := c .GetResourceTypes (ctx , nil )
324+ if err != nil {
325+ return nil , err
326+ }
327+
328+ c .resourceTypesCache = types
329+ return types , nil
330+ }
331+
332+ // GetResourceTypeCached returns a cached resource type by ID, fetching from API if not in cache
333+ func (c * Client ) GetResourceTypeCached (ctx context.Context , typeID string ) (* ResourceType , error ) {
334+ // First check the cache
335+ if c .resourceTypesCache != nil {
336+ for i := range c .resourceTypesCache {
337+ if c .resourceTypesCache [i ].ID == typeID {
338+ return & c .resourceTypesCache [i ], nil
339+ }
340+ }
341+ }
342+
343+ // Populate cache and search again
344+ types , err := c .GetResourceTypesCached (ctx )
345+ if err != nil {
346+ return nil , err
347+ }
348+
349+ for i := range types {
350+ if types [i ].ID == typeID {
351+ return & types [i ], nil
352+ }
353+ }
354+
355+ return nil , fmt .Errorf ("resource type not found: %v" , typeID )
356+ }
357+
358+ // GetResourceTypeBySlugCached returns a cached resource type by slug
359+ func (c * Client ) GetResourceTypeBySlugCached (ctx context.Context , slug string ) (* ResourceType , error ) {
360+ types , err := c .GetResourceTypesCached (ctx )
361+ if err != nil {
362+ return nil , err
363+ }
364+
365+ for i := range types {
366+ if types [i ].Slug == slug {
367+ return & types [i ], nil
368+ }
369+ }
370+
371+ return nil , fmt .Errorf ("resource type not found: %v" , slug )
372+ }
373+
374+ // GetMetadataKeysCached returns cached metadata keys, fetching from API if cache is empty
375+ func (c * Client ) GetMetadataKeysCached (ctx context.Context ) ([]MetadataKey , error ) {
376+ if c .metadataKeysCache != nil {
377+ return c .metadataKeysCache , nil
378+ }
379+
380+ keys , err := c .GetMetadataKeys (ctx , & GetMetadataKeysOptions {
381+ ContainMetadataPrivateKeys : true ,
382+ })
383+ if err != nil {
384+ return nil , err
385+ }
386+
387+ c .metadataKeysCache = keys
388+ return keys , nil
389+ }
390+
391+ // GetDecryptedMetadataKeyCached returns a cached decrypted metadata key by ID
392+ // If not in cache, it will fetch and decrypt the key
393+ func (c * Client ) GetDecryptedMetadataKeyCached (ctx context.Context , id string ) (* crypto.Key , error ) {
394+ // Check decrypted key cache first
395+ if key , ok := c .decryptedMetadataKeysCache [id ]; ok {
396+ return key , nil
397+ }
398+
399+ // Get metadata keys (from cache or API)
400+ keys , err := c .GetMetadataKeysCached (ctx )
401+ if err != nil {
402+ return nil , fmt .Errorf ("Get Metadata Keys: %w" , err )
403+ }
404+
405+ // Find the key with matching ID
406+ var metadataKey * MetadataKey
407+ for i := range keys {
408+ if keys [i ].ID == id {
409+ metadataKey = & keys [i ]
410+ break
411+ }
412+ }
413+
414+ if metadataKey == nil {
415+ return nil , fmt .Errorf ("Metadata key not found: %v" , id )
416+ }
417+
418+ if len (metadataKey .MetadataPrivateKeys ) == 0 {
419+ return nil , fmt .Errorf ("No Metadata Private key for our user" )
420+ }
421+
422+ // Find our user's private key
423+ var privMetadata * MetadataPrivateKey
424+ for i := range metadataKey .MetadataPrivateKeys {
425+ if metadataKey .MetadataPrivateKeys [i ].UserID != nil && * metadataKey .MetadataPrivateKeys [i ].UserID == c .userID {
426+ privMetadata = & metadataKey .MetadataPrivateKeys [i ]
427+ break
428+ }
429+ }
430+
431+ if privMetadata == nil {
432+ return nil , fmt .Errorf ("No Metadata Private key for our user id: %v" , c .userID )
433+ }
434+
435+ decPrivMetadatakey , err := c .DecryptMessage (privMetadata .Data )
436+ if err != nil {
437+ return nil , fmt .Errorf ("Decrypt Metadata Private Key Data: %w" , err )
438+ }
439+
440+ var data MetadataPrivateKeyData
441+ err = json .Unmarshal ([]byte (decPrivMetadatakey ), & data )
442+ if err != nil {
443+ return nil , fmt .Errorf ("Parse Metadata Private Key Data: %w" , err )
444+ }
445+
446+ metadataPrivateKeyObj , err := GetPrivateKeyFromArmor (data .ArmoredKey , []byte (data .Passphrase ))
447+ if err != nil {
448+ return nil , fmt .Errorf ("Get Metadata Private Key: %w" , err )
449+ }
450+
451+ // Cache the decrypted key
452+ c .decryptedMetadataKeysCache [id ] = metadataPrivateKeyObj
453+
454+ return metadataPrivateKeyObj , nil
455+ }
456+
457+ // GetSessionKey retrieves a cached session key for a metadata key ID
458+ func (c * Client ) GetSessionKey (metadataKeyID string ) * crypto.SessionKey {
459+ return c .sessionKeyCache [metadataKeyID ]
460+ }
461+
462+ // SetSessionKey stores a session key in the cache for a metadata key ID
463+ func (c * Client ) SetSessionKey (metadataKeyID string , sessionKey * crypto.SessionKey ) {
464+ c .sessionKeyCache [metadataKeyID ] = sessionKey
465+ }
0 commit comments