Class: Books::StandardClient

Inherits:
Object
  • Object
show all
Defined in:
lib/books/client.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(books_client: nil, books_authority_client: nil, connector: nil, eddsa_public_key_path:, eddsa_private_key_path:) ⇒ StandardClient

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


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 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

Instance Attribute Details

#books_authority_clientObject (readonly)

Returns the value of attribute books_authority_client.



10
11
12
# File 'lib/books/client.rb', line 10

def books_authority_client
  @books_authority_client
end

#books_clientObject (readonly)

Returns the value of attribute books_client.



10
11
12
# File 'lib/books/client.rb', line 10

def books_client
  @books_client
end

#eddsa_private_keyObject (readonly)

Returns the value of attribute eddsa_private_key.



10
11
12
# File 'lib/books/client.rb', line 10

def eddsa_private_key
  @eddsa_private_key
end

#eddsa_public_keyObject (readonly)

Returns the value of attribute eddsa_public_key.



10
11
12
# File 'lib/books/client.rb', line 10

def eddsa_public_key
  @eddsa_public_key
end

Instance Method Details

#create_book(req) ⇒ Object



72
73
74
75
76
77
78
# 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) ⇒ Object



68
69
70
# File 'lib/books/client.rb', line 68

def create_denomination(req)
  @books_client.https_rpc(:create_denomination, req)
end

#get_books_matching(req) ⇒ Object



54
55
56
# File 'lib/books/client.rb', line 54

def get_books_matching(req)
  @books_client.https_rpc(:get_books_matching, req)
end

#journal(req) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 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) ⇒ Object



64
65
66
# File 'lib/books/client.rb', line 64

def register_client(req)
  @books_client.https_rpc(:register_client, req)
end

#register_myselfObject



58
59
60
61
62
# File 'lib/books/client.rb', line 58

def register_myself
  register_client({
    public_key: @eddsa_public_key_data
  })
end