Class TokenStore

java.lang.Object
com.ultikits.ultitools.utils.TokenStore

final class TokenStore extends Object
The only thing that writes the UltiCloud credential to disk.

Package-private, with a package-private constructor -- a CloudSession is the only thing in this codebase that constructs one (D-18). This is deliberately a thin wrapper, not a second implementation of file I/O: every operation below delegates to CredentialStore, this package's actual single owner of credentials.json on disk (its own structural test, CredentialStoreTest#onlyCredentialStoreTouchesTheCredentialFileDirectly, asserts that no class other than CredentialStore opens a reader or writer on that file -- delegating rather than reimplementing keeps this class outside that scan, and correctly so: this class owns who may call the write, not how the write happens).

Since:
6.3.0
  • Field Details

    • GSON

      private static final com.google.gson.Gson GSON
  • Constructor Details

    • TokenStore

      TokenStore()
  • Method Details

    • save

      void save(TokenEntity token) throws IOException
      Persists token, replacing whatever cloud_token entry currently exists in the credential document. Every other field in the document (server UUID, etc.) is left untouched -- CredentialStore.update(java.util.function.UnaryOperator<java.util.Map<java.lang.String, java.lang.Object>>) reads the existing document first.
      Parameters:
      token - the token to persist
      Throws:
      IOException - if the underlying write fails
    • clearIfMatches

      void clearIfMatches(TokenEntity expected) throws IOException
      Removes the persisted cloud_token entry, but ONLY if it still matches expected -- i.e. nothing else has overwritten it since expected was this session's own last-known token.

      Round-1 external review finding (16-10, PR #464): a plain, unconditional clear here is a compare-and-delete's absence, not its presence. credentials.json is one shared document across every session that has ever existed (D-16 gives each session its own lifecycle, not its own file). If a stale session's logout races a fresh login whose commit lands on the shared document first, an unconditional clear removes the FRESH credential -- the exact defect this method exists to prevent. Comparing against expected (the calling session's own token, captured before teardown) means a clear only ever removes what that specific session itself is the one that wrote — anything written afterward, by anyone else, survives.

      Parameters:
      expected - the token this session itself believes is (or was) persisted; if the disk's current cloud_token does not match it (by access token value), nothing is removed
      Throws:
      IOException - if the underlying write fails
    • matchesAccessToken

      private static boolean matchesAccessToken(Object savedRaw, TokenEntity expected)
      Parameters:
      savedRaw - the raw cloud_token value read from the credential document (a Map once Gson has deserialized it, or null/anything else if absent or malformed)
      expected - the token to compare against
      Returns:
      true if savedRaw is a map whose access_token entry equals expected's access token
    • readRaw

      Reads the raw credential document. Exposed rather than a parsed TokenEntity because the caller (CloudSession.loadFromDisk()) needs to distinguish "absent" from "torn" and log accordingly -- collapsing that here would lose the distinction CredentialStore.ReadResult exists to preserve.
      Returns:
      the raw read result
    • parseToken

      TokenEntity parseToken(Map<String,Object> data)
      Parses the cloud_token entry out of an already-read document, or null if absent, unparseable, or missing an access token.
      Parameters:
      data - a parsed credential document, e.g. from readRaw()
      Returns:
      the parsed token, or null