class Books::StandardClient
Attributes
books_client[R]
eddsa_private_key[R]
eddsa_public_key[R]
Public Class Methods
new(books_client: nil, books_authority_client: nil, connector: nil, eddsa_public_key_path:, eddsa_private_key_path:)
click to toggle source
Instantiate a new client that can connect to Books
.
** eddsa_public_key_path and eddsa_private_key_path (required) ** :
Both are paths to your eddsa keys you intend to use to sign journal entries. The private key will be used to sign journal entries as they are sent, while the public key can be used to verify journal entries afterwards. Note that these are generally not the same keys used to intitiate TLS.
** connector ** :
A connector from which we can request the clients "books" and "booksAuthority". This is only required if either books_client or books_authority_client are not provided. Connectors are provided by the square_connector gem or from sq/common.
** books_client
and books_authority_client
(optional) ** :
RPC clients that would otherwise be provided by the connector. Helpful for testing. If provided, will take precedence over what would have been returned by the connector
# File lib/books/client.rb, line 31 def initialize(books_client: nil, books_authority_client: nil, connector: nil, eddsa_public_key_path:, eddsa_private_key_path:) @books_client = books_client || begin fail "Neither connector nor books_client given" unless connector books_http_client = connector.create(:books) Sq::Protos::RpcClient.new(books_http_client, Squareup::Books::Service::BooksService) end @books_authority_client = books_authority_client || begin fail "Neither connector nor books_authority_client given" unless connector books_authority_http_client = connector.create(:booksAuthority) Sq::Protos::RpcClient.new(books_authority_http_client, Squareup::Booksauthority::Service::BooksAuthorityService) end @eddsa_private_key = Ed25519::SigningKey.new(extract_key(eddsa_private_key_path, "ED25519 PRIVATE KEY")) @eddsa_public_key_data = File.read(eddsa_public_key_path) # want PEM format @eddsa_public_key = Ed25519::VerifyKey.new(extract_key(eddsa_public_key_path, "ED25519 PUBLIC KEY")) end
Public Instance Methods
create_book(req)
click to toggle source
# File lib/books/client.rb, line 72 def create_book(req) bas_response = @books_authority_client.https_rpc(:generate_sskg, {}) with_sskg = req.dup with_sskg[:first_sskg_key] = bas_response[:first_key] with_sskg[:root_sskg_token] = bas_response[:root_sskg_token] @books_client.https_rpc(:create_book, with_sskg) end
create_denomination(req)
click to toggle source
# File lib/books/client.rb, line 68 def create_denomination(req) @books_client.https_rpc(:create_denomination, req) end
get_books_matching(req)
click to toggle source
# File lib/books/client.rb, line 54 def get_books_matching(req) @books_client.https_rpc(:get_books_matching, req) end
journal(req)
click to toggle source
# File lib/books/client.rb, line 80 def journal(req) raise "Journal entry type not provided" unless req[:journal_entry_type] raise "Journal idempotence token not provided" unless req[:idempotence_token] raise "Journal entries not provided" unless req[:entries] && req[:entries].size > 1 total = req[:entries].map do |entry| raise "Must set exactly one of to_amount or from_amount" unless (entry[:to_amount] ^ entry[:from_amount]) entry[:to_amount] - entry[:from_amount] end.sum raise "Total change in book entry amounts is not 0" unless total == 0 raise "The signature field must not be set (the SDK will assign this field for you)" if req[:signature] # sign the request body jreq = Squareup::Books::Service::JournalRequest.new(req) encoded_proto = jreq.encode signature = @eddsa_private_key.sign(encoded_proto) req[:signature] = signature journal_response = @books_client.https_rpc(:journal, req) if journal_response.status != Squareup::Books::Service::JournalStatus::JOURNAL_SUCCESS raise "Journaling error received: #{journal_resp.status}" end journal_response end
register_client(req)
click to toggle source
# File lib/books/client.rb, line 64 def register_client(req) @books_client.https_rpc(:register_client, req) end
register_myself()
click to toggle source
# File lib/books/client.rb, line 58 def register_myself register_client({ public_key: @eddsa_public_key_data }) end
Private Instance Methods
extract_key(pem_filepath, expected_pem_header)
click to toggle source
Given a filepath, read the file as a PEM file. Assert that the given header is present in the PEM header and footer.
# File lib/books/client.rb, line 112 def extract_key(pem_filepath, expected_pem_header) pem_data = File.read(pem_filepath) contents = pem_data.split("\n") raise "Invalid PEM file, too short" unless contents.size > 2 unless contents[0].include?(expected_pem_header) raise "Header for #{pem_filepath} isn't what we expected. Is it a #{expected_pem_header} ?" end unless contents[contents.length - 1].include?(expected_pem_header) raise "Footer for #{pem_filepath} isn't what we expected. Is it a #{expected_pem_header} ?" end base64Encoded = contents[1..contents.size-2].join("") return Base64.decode64(base64Encoded) end