mixin_bot 0.12.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mixin_bot/api/address.rb +21 -0
  3. data/lib/mixin_bot/api/app.rb +5 -11
  4. data/lib/mixin_bot/api/asset.rb +9 -16
  5. data/lib/mixin_bot/api/attachment.rb +27 -22
  6. data/lib/mixin_bot/api/auth.rb +34 -56
  7. data/lib/mixin_bot/api/blaze.rb +4 -3
  8. data/lib/mixin_bot/api/conversation.rb +29 -49
  9. data/lib/mixin_bot/api/encrypted_message.rb +19 -19
  10. data/lib/mixin_bot/api/inscription.rb +71 -0
  11. data/lib/mixin_bot/api/legacy_collectible.rb +140 -0
  12. data/lib/mixin_bot/api/legacy_multisig.rb +87 -0
  13. data/lib/mixin_bot/api/legacy_output.rb +50 -0
  14. data/lib/mixin_bot/api/legacy_payment.rb +31 -0
  15. data/lib/mixin_bot/api/legacy_snapshot.rb +39 -0
  16. data/lib/mixin_bot/api/legacy_transaction.rb +173 -0
  17. data/lib/mixin_bot/api/legacy_transfer.rb +42 -0
  18. data/lib/mixin_bot/api/me.rb +13 -17
  19. data/lib/mixin_bot/api/message.rb +13 -10
  20. data/lib/mixin_bot/api/multisig.rb +17 -222
  21. data/lib/mixin_bot/api/output.rb +48 -0
  22. data/lib/mixin_bot/api/payment.rb +9 -20
  23. data/lib/mixin_bot/api/pin.rb +57 -65
  24. data/lib/mixin_bot/api/rpc.rb +12 -14
  25. data/lib/mixin_bot/api/snapshot.rb +15 -29
  26. data/lib/mixin_bot/api/tip.rb +43 -0
  27. data/lib/mixin_bot/api/transaction.rb +295 -60
  28. data/lib/mixin_bot/api/transfer.rb +69 -31
  29. data/lib/mixin_bot/api/user.rb +88 -53
  30. data/lib/mixin_bot/api/withdraw.rb +52 -53
  31. data/lib/mixin_bot/api.rb +81 -46
  32. data/lib/mixin_bot/cli/api.rb +149 -5
  33. data/lib/mixin_bot/cli/utils.rb +14 -4
  34. data/lib/mixin_bot/cli.rb +13 -10
  35. data/lib/mixin_bot/client.rb +74 -127
  36. data/lib/mixin_bot/configuration.rb +98 -0
  37. data/lib/mixin_bot/nfo.rb +174 -0
  38. data/lib/mixin_bot/transaction.rb +524 -0
  39. data/lib/mixin_bot/utils/address.rb +121 -0
  40. data/lib/mixin_bot/utils/crypto.rb +218 -0
  41. data/lib/mixin_bot/utils/decoder.rb +56 -0
  42. data/lib/mixin_bot/utils/encoder.rb +63 -0
  43. data/lib/mixin_bot/utils.rb +8 -109
  44. data/lib/mixin_bot/uuid.rb +41 -0
  45. data/lib/mixin_bot/version.rb +1 -1
  46. data/lib/mixin_bot.rb +39 -14
  47. data/lib/mvm/bridge.rb +2 -19
  48. data/lib/mvm/client.rb +11 -33
  49. data/lib/mvm/nft.rb +4 -4
  50. data/lib/mvm/registry.rb +9 -9
  51. data/lib/mvm/scan.rb +3 -5
  52. data/lib/mvm.rb +5 -6
  53. metadata +77 -103
  54. data/lib/mixin_bot/api/collectible.rb +0 -138
  55. data/lib/mixin_bot/utils/nfo.rb +0 -176
  56. data/lib/mixin_bot/utils/transaction.rb +0 -478
  57. data/lib/mixin_bot/utils/uuid.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf2e7ef08c38a52d5d31ce1be5a0531f13680e31cb5e7f11cd6e1582436d8711
4
- data.tar.gz: '08cfa89514d3f102cdd064cfb3c3367cf2166292a3abc854481320a2fb610d15'
3
+ metadata.gz: 4257bfdffc20e27ffab5ce9da23080be113a552623f5022775f3cc8a6cc6db0c
4
+ data.tar.gz: 7f29a034845b45715e33b3b51e28be996408fcff145538025a243fb74d42b482
5
5
  SHA512:
6
- metadata.gz: a5f7af8574ea545b899bd2081923dd75e0b2ef2288346fb8e8d842b642ef596c626370d9a5140a695c267db4281e4c51239cce2d55f5edb87ed33127c76c379b
7
- data.tar.gz: b2393b4a392ff025b0e6d58c545018bd4cafb26e9fb130bba8938e42d4850a6f2b5d0244d887f6dae8d8f53fcb000819737ea71d999add7e175637c7e2d591d1
6
+ metadata.gz: 18e9d94005f235f827ce4e7598a2b2ddf13f48b296d9af46e4d6b2550e795c30f805c40b815352c159f7f2aa7b35c0a4e93ea0787889175c373e931720b5dc17
7
+ data.tar.gz: 56e0c4651199912fd4ed4bef7eb96cc22de1cd30842b7d8e767811ece926e880984a0f2734db19d4f1c48464c037e3b3d9c22b61be204c8a83ffd0f926203e37
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ class API
5
+ module Address
6
+ def safe_deposit_entries(**kwargs)
7
+ path = '/safe/deposit/entries'
8
+
9
+ members = [kwargs[:members]] if kwargs[:members].is_a? String
10
+
11
+ payload = {
12
+ members:,
13
+ threshold: kwargs[:threshold] || 1,
14
+ chain_id: kwargs[:chain_id]
15
+ }
16
+
17
+ client.post path, **payload, access_token: kwargs[:access_token]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -6,25 +6,19 @@ module MixinBot
6
6
  def add_favorite_app(app_id, access_token: nil)
7
7
  path = format('/apps/%<id>s/favorite', id: app_id)
8
8
 
9
- access_token ||= access_token('POST', path)
10
- authorization = format('Bearer %<access_token>s', access_token: access_token)
11
- client.post(path, headers: { 'Authorization': authorization })
9
+ client.post path, access_token:
12
10
  end
13
11
 
14
12
  def remove_favorite_app(app_id, access_token: nil)
15
13
  path = format('/apps/%<id>s/unfavorite', id: app_id)
16
14
 
17
- access_token ||= access_token('POST', path)
18
- authorization = format('Bearer %<access_token>s', access_token: access_token)
19
- client.post(path, headers: { 'Authorization': authorization })
15
+ client.post path, access_token:
20
16
  end
21
17
 
22
- def favorite_apps(user_id, access_token: nil)
23
- path = format('/users/%<id>s/apps/favorite', id: user_id)
18
+ def favorite_apps(user_id = nil, access_token: nil)
19
+ path = format('/users/%<id>s/apps/favorite', id: user_id || config.app_id)
24
20
 
25
- access_token ||= access_token('GET', path, '')
26
- authorization = format('Bearer %<access_token>s', access_token: access_token)
27
- client.get(path, headers: { 'Authorization': authorization })
21
+ client.get path, access_token:
28
22
  end
29
23
  end
30
24
  end
@@ -6,31 +6,24 @@ module MixinBot
6
6
  # https://developers.mixin.one/api/alpha-mixin-network/read-assets/
7
7
  def assets(access_token: nil)
8
8
  path = '/assets'
9
- access_token ||= access_token('GET', path, '')
10
- authorization = format('Bearer %<access_token>s', access_token: access_token)
11
- client.get(path, headers: { 'Authorization': authorization })
9
+ client.get path, access_token:
12
10
  end
13
- alias read_assets assets
14
11
 
15
12
  # https://developers.mixin.one/api/alpha-mixin-network/read-asset/
16
13
  def asset(asset_id, access_token: nil)
17
- path = format('/assets/%<asset_id>s', asset_id: asset_id)
18
- access_token ||= access_token('GET', path, '')
19
- authorization = format('Bearer %<access_token>s', access_token: access_token)
20
- client.get(path, headers: { 'Authorization': authorization })
14
+ path = format('/assets/%<asset_id>s', asset_id:)
15
+ client.get path, access_token:
21
16
  end
22
- alias read_asset asset
23
17
 
24
18
  # https://developers.mixin.one/document/wallet/api/ticker
25
- def ticker(asset_id, offset, access_token: nil)
26
- offset = DateTime.rfc3339 offset if offset.is_a? String
19
+ def ticker(asset_id, **kwargs)
20
+ offset = kwargs[:offset]
21
+ offset = DateTime.rfc3339(offset) if offset.is_a? String
27
22
  offset = offset.rfc3339 if offset.is_a?(DateTime) || offset.is_a?(Time)
28
- path = format('/ticker?asset=%<asset_id>s&offset=%<offset>s', asset_id: asset_id, offset: offset)
29
- access_token ||= access_token('GET', path, '')
30
- authorization = format('Bearer %<access_token>s', access_token: access_token)
31
- client.get(path, headers: { 'Authorization': authorization })
23
+
24
+ path = '/ticker'
25
+ client.get path, asset_id:, offset:, access_token: kwargs[:access_token]
32
26
  end
33
- alias read_ticker ticker
34
27
  end
35
28
  end
36
29
  end
@@ -3,7 +3,6 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Attachment
6
- # https://developers.mixin.one/api/beta-mixin-message/create-attachment/
7
6
  # Sample Response
8
7
  # {
9
8
  # "data":{
@@ -14,38 +13,44 @@ module MixinBot
14
13
  # }
15
14
  # }
16
15
  # Once get the upload_url, use it to upload the your file via PUT request
17
- def create_attachment
16
+ def create_attachment(access_token: nil)
18
17
  path = '/attachments'
19
- access_token ||= access_token('POST', path, {}.to_json)
20
- authorization = format('Bearer %<access_token>s', access_token: access_token)
21
- client.post(path, headers: { 'Authorization': authorization }, json: {})
18
+ client.post path, access_token:
22
19
  end
23
20
 
24
21
  def upload_attachment(file)
25
22
  attachment = create_attachment['data']
26
23
 
27
- HTTP
28
- .timeout(connect: 5, write: 5, read: 5)
29
- .request(
30
- :put,
31
- attachment.delete('upload_url'),
32
- {
33
- body: file,
34
- headers: {
35
- 'x-amz-acl': 'public-read',
36
- 'Content-Type': 'application/octet-stream'
37
- }
38
- }
39
- )
24
+ url = attachment.delete('upload_url')
25
+ conn = Faraday.new(url:) do |f|
26
+ f.adapter :net_http
27
+
28
+ f.request :multipart
29
+ f.request :retry
30
+ f.response :raise_error
31
+ f.response :logger if config.debug
32
+ end
33
+
34
+ conn.put(url) do |req|
35
+ req.headers = {
36
+ 'x-amz-acl': 'public-read',
37
+ 'Content-Type': 'application/octet-stream'
38
+ }
39
+ req.body = Faraday::UploadIO.new(file, 'octet/stream')
40
+
41
+ if file.respond_to?(:length)
42
+ req.headers['Content-Length'] = file.length.to_s
43
+ elsif file.respond_to?(:stat)
44
+ req.headers['Content-Length'] = file.stat.size.to_s
45
+ end
46
+ end
40
47
 
41
48
  attachment
42
49
  end
43
50
 
44
- def read_attachment(attachment_id)
51
+ def attachment(attachment_id, access_token: nil)
45
52
  path = format('/attachments/%<id>s', id: attachment_id)
46
- access_token ||= access_token('GET', path, '')
47
- authorization = format('Bearer %<access_token>s', access_token: access_token)
48
- client.get(path, headers: { 'Authorization': authorization })
53
+ client.get path, access_token:
49
54
  end
50
55
  end
51
56
  end
@@ -3,85 +3,60 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Auth
6
- def access_token(method, uri, body = '', exp_in: 600, scp: 'FULL')
7
- sig = Digest::SHA256.hexdigest(method + uri + body.to_s)
8
- iat = Time.now.utc.to_i
9
- exp = (Time.now.utc + exp_in).to_i
10
- jti = SecureRandom.uuid
11
- payload = {
12
- uid: client_id,
13
- sid: session_id,
14
- iat: iat,
15
- exp: exp,
16
- jti: jti,
17
- sig: sig,
18
- scp: scp
19
- }
20
- case key_type
21
- when :ed25519
22
- jwk = JOSE::JWK.from_okp [:Ed25519, private_key]
23
- jws = JOSE::JWS.from({ 'alg' => 'EdDSA' })
24
- when :rsa
25
- jwk = JOSE::JWK.from_pem private_key
26
- jws = JOSE::JWS.from({ 'alg' => 'RS512' })
27
- end
28
-
29
- jwt = JOSE::JWT.from payload
30
- JOSE::JWT.sign(jwk, jws, jwt).compact
31
- end
32
-
33
6
  def oauth_token(code)
34
7
  path = 'oauth/token'
35
8
  payload = {
36
- client_id: client_id,
37
- client_secret: client_secret,
38
- code: code
9
+ client_id: config.app_id,
10
+ client_secret: config.client_secret,
11
+ code:
39
12
  }
40
- r = client.post(path, json: payload)
41
-
42
- raise r.inspect if r['error'].present?
43
-
44
- r['data']&.[]('access_token')
13
+ client.post path, **payload
45
14
  end
46
15
 
47
16
  def request_oauth(scope = nil)
48
- scope ||= (MixinBot.scope || 'PROFILE:READ')
17
+ scope ||= 'PROFILE:READ'
49
18
  format(
50
- 'https://mixin.one/oauth/authorize?client_id=%<client_id>s&scope=%<scope>s',
51
- client_id: client_id,
52
- scope: scope
19
+ 'https://mixin.one/oauth/authorize?client_id=%<app_id>s&scope=%<scope>s',
20
+ app_id: config.app_id,
21
+ scope:
53
22
  )
54
23
  end
55
24
 
56
25
  def authorize_code(**kwargs)
57
- path = '/oauth/authorize'
58
26
  data = authorization_data(
59
- kwargs[:user_id],
27
+ kwargs[:app_id],
60
28
  kwargs[:scope] || ['PROFILE:READ']
61
29
  )
62
30
 
31
+ path = '/oauth/authorize'
32
+ pin = kwargs[:pin] || config.pin
63
33
  payload = {
64
34
  authorization_id: data['authorization_id'],
65
35
  scopes: data['scopes'],
66
36
  pin_base64: encrypt_pin(kwargs[:pin])
67
37
  }
68
38
 
69
- access_token = kwargs[:access_token]
70
- access_token ||= access_token('POST', path, payload.to_json)
71
- authorization = format('Bearer %<access_token>s', access_token: access_token)
72
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
39
+ raise ArgumentError, 'pin is required' if pin.blank?
40
+
41
+ payload[:pin_base64] = if pin.size > 6
42
+ encrypt_tip_pin(pin, 'TIP:OAUTH:APPROVE:', data['scopes'], data['authorization_id'])
43
+ else
44
+ encrypt_pin(pin)
45
+ end
46
+
47
+ client.post path, **payload, access_token: kwargs[:access_token]
73
48
  end
74
49
 
75
- def authorization_data(user_id, scope = ['PROFILE:READ'])
76
- @_client_id = user_id
50
+ def authorization_data(app_id, scope = ['PROFILE:READ'])
51
+ @_app_id = app_id
77
52
  @_scope = scope.join(' ')
78
53
  EM.run do
79
54
  start_blaze_connect do
80
- def on_open(ws, _event)
81
- ws.send write_ws_message(
55
+ def on_open(websocket, _event) # rubocop:disable Lint/NestedMethodDefinition
56
+ websocket.send write_ws_message(
82
57
  action: 'REFRESH_OAUTH_CODE',
83
58
  params: {
84
- client_id: @_client_id,
59
+ client_id: @_app_id,
85
60
  scope: @_scope,
86
61
  authorization_id: '',
87
62
  code_challenge: ''
@@ -89,18 +64,21 @@ module MixinBot
89
64
  )
90
65
  end
91
66
 
92
- def on_message(ws, event)
93
- raw = JSON.parse read_ws_message(event.data)
94
- @_data = raw['data']
95
- ws.close
67
+ def on_message(websocket, event) # rubocop:disable Lint/NestedMethodDefinition
68
+ raw = JSON.parse ws_message(event.data)
69
+ @_data = raw
70
+ websocket.close
96
71
  end
97
72
 
98
- def on_close(_ws, _event)
73
+ def on_close(_websocket, _event) # rubocop:disable Lint/NestedMethodDefinition
99
74
  EM.stop_event_loop
100
75
  end
101
76
  end
102
77
  end
103
- @_data
78
+
79
+ raise MixinBot::RequestError, @_data if @_data['error'].present?
80
+
81
+ @_data['data']
104
82
  end
105
83
  end
106
84
  end
@@ -5,9 +5,10 @@ module MixinBot
5
5
  module Blaze
6
6
  def blaze
7
7
  access_token = access_token('GET', '/', '')
8
- authorization = format('Bearer %<access_token>s', access_token: access_token)
8
+
9
+ authorization = format('Bearer %<access_token>s', access_token:)
9
10
  Faye::WebSocket::Client.new(
10
- format('wss://%<host>s/', host: blaze_host),
11
+ format('wss://%<host>s/', host: config.blaze_host),
11
12
  ['Mixin-Blaze-1'],
12
13
  headers: { 'Authorization' => authorization },
13
14
  ping: 60
@@ -31,7 +32,7 @@ module MixinBot
31
32
  if defined? on_message
32
33
  on_message ws, event
33
34
  else
34
- raw = JSON.parse read_ws_message(event.data)
35
+ raw = JSON.parse ws_message(event.data)
35
36
  p [Time.now.to_s, :message, raw&.[]('action')]
36
37
 
37
38
  ws.send acknowledge_message_receipt(raw['data']['message_id']) unless raw&.[]('data')&.[]('message_id').nil?
@@ -3,77 +3,67 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Conversation
6
- def conversation(conversation_id)
7
- path = format('/conversations/%<conversation_id>s', conversation_id: conversation_id)
8
- access_token ||= access_token('GET', path, '')
9
- authorization = format('Bearer %<access_token>s', access_token: access_token)
10
- client.get(path, headers: { 'Authorization': authorization })
6
+ def conversation(conversation_id, access_token: nil)
7
+ path = format('/conversations/%<conversation_id>s', conversation_id:)
8
+ client.get path, access_token:
11
9
  end
12
- alias read_conversation conversation
13
10
 
14
11
  def conversation_by_user_id(user_id)
15
- conversation_id = unique_conversation_id(user_id)
16
- read_conversation(conversation_id)
12
+ conversation_id = unique_uuid user_id
13
+ conversation conversation_id
17
14
  end
18
- alias read_conversation_by_user_id conversation_by_user_id
19
15
 
20
- def create_conversation(category:, conversation_id:, participants:, name: nil, access_token: nil)
16
+ def create_conversation(**kwargs)
21
17
  path = '/conversations'
22
18
  payload = {
23
- category: category,
24
- conversation_id: conversation_id || SecureRandom.uuid,
25
- name: name,
26
- participants: participants
27
- }
19
+ category: kwargs[:category],
20
+ conversation_id: kwargs[:conversation_id] || SecureRandom.uuid,
21
+ name: kwargs[:name],
22
+ participants: kwargs[:participants]
23
+ }.compact_blank
28
24
 
29
- access_token ||= access_token('POST', path, payload.to_json)
30
- authorization = format('Bearer %<access_token>s', access_token: access_token)
31
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
25
+ client.post path, **payload, access_token: kwargs[:access_token]
32
26
  end
33
27
 
34
28
  def create_group_conversation(user_ids:, name:, conversation_id: nil, access_token: nil)
35
29
  create_conversation(
36
30
  category: 'GROUP',
37
- conversation_id: conversation_id,
38
- name: name,
31
+ conversation_id:,
32
+ name:,
39
33
  participants: user_ids.map(&->(participant) { { user_id: participant } }),
40
- access_token: access_token
34
+ access_token:
41
35
  )
42
36
  end
43
37
 
44
38
  def create_contact_conversation(user_id, access_token: nil)
45
39
  create_conversation(
46
40
  category: 'CONTACT',
47
- conversation_id: unique_conversation_id(user_id),
41
+ conversation_id: unique_uuid(user_id),
48
42
  participants: [
49
43
  {
50
- user_id: user_id
44
+ user_id:
51
45
  }
52
46
  ],
53
- access_token: access_token
47
+ access_token:
54
48
  )
55
49
  end
56
50
 
57
51
  def update_group_conversation_name(name:, conversation_id:, access_token: nil)
58
52
  path = format('/conversations/%<id>s', id: conversation_id)
59
53
  payload = {
60
- name: name
54
+ name:
61
55
  }
62
56
 
63
- access_token ||= access_token('POST', path, payload.to_json)
64
- authorization = format('Bearer %<access_token>s', access_token: access_token)
65
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
57
+ client.post path, **payload, access_token:
66
58
  end
67
59
 
68
60
  def update_group_conversation_announcement(announcement:, conversation_id:, access_token: nil)
69
61
  path = format('/conversations/%<id>s', id: conversation_id)
70
62
  payload = {
71
- announcement: announcement
63
+ announcement:
72
64
  }
73
65
 
74
- access_token ||= access_token('POST', path, payload.to_json)
75
- authorization = format('Bearer %<access_token>s', access_token: access_token)
76
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
66
+ client.post path, **payload, access_token:
77
67
  end
78
68
 
79
69
  # participants = [{ user_id: "" }]
@@ -81,9 +71,7 @@ module MixinBot
81
71
  path = format('/conversations/%<id>s/participants/ADD', id: conversation_id)
82
72
  payload = user_ids.map(&->(participant) { { user_id: participant } })
83
73
 
84
- access_token ||= access_token('POST', path, payload.to_json)
85
- authorization = format('Bearer %<access_token>s', access_token: access_token)
86
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
74
+ client.post path, *payload, access_token:
87
75
  end
88
76
 
89
77
  # participants = [{ user_id: "" }]
@@ -91,25 +79,19 @@ module MixinBot
91
79
  path = format('/conversations/%<id>s/participants/REMOVE', id: conversation_id)
92
80
  payload = user_ids.map(&->(participant) { { user_id: participant } })
93
81
 
94
- access_token ||= access_token('POST', path, payload.to_json)
95
- authorization = format('Bearer %<access_token>s', access_token: access_token)
96
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
82
+ client.post path, *payload, access_token:
97
83
  end
98
84
 
99
85
  def exit_conversation(conversation_id, access_token: nil)
100
86
  path = format('/conversations/%<id>s/exit', id: conversation_id)
101
87
 
102
- access_token ||= access_token('POST', path)
103
- authorization = format('Bearer %<access_token>s', access_token: access_token)
104
- client.post(path, headers: { 'Authorization': authorization })
88
+ client.post path, access_token:
105
89
  end
106
90
 
107
91
  def rotate_conversation(conversation_id, access_token: nil)
108
92
  path = format('/conversations/%<id>s/rotate', id: conversation_id)
109
93
 
110
- access_token ||= access_token('POST', path)
111
- authorization = format('Bearer %<access_token>s', access_token: access_token)
112
- client.post(path, headers: { 'Authorization': authorization })
94
+ client.post path, access_token:
113
95
  end
114
96
 
115
97
  # participants = [{ user_id: "", role: "ADMIN" }]
@@ -117,14 +99,12 @@ module MixinBot
117
99
  path = format('/conversations/%<id>s/participants/ROLE', id: conversation_id)
118
100
  payload = participants
119
101
 
120
- access_token ||= access_token('POST', path, payload.to_json)
121
- authorization = format('Bearer %<access_token>s', access_token: access_token)
122
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
102
+ client.post path, *payload, access_token:
123
103
  end
124
104
 
125
105
  def unique_uuid(user_id, opponent_id = nil)
126
- opponent_id ||= client_id
127
- MixinBot::Utils.unique_uuid user_id, opponent_id
106
+ opponent_id ||= config.app_id
107
+ MixinBot.utils.unique_uuid user_id, opponent_id
128
108
  end
129
109
  alias unique_conversation_id unique_uuid
130
110
  end
@@ -90,11 +90,11 @@ module MixinBot
90
90
  category: options[:category],
91
91
  quote_message_id: options[:quote_message_id],
92
92
  message_id: options[:message_id] || SecureRandom.uuid,
93
- data_base64: data_base64,
94
- checksum: checksum,
93
+ data_base64:,
94
+ checksum:,
95
95
  recipient_sessions: session_ids.map(&->(s) { { session_id: s } }),
96
96
  silent: false
97
- }
97
+ }.compact
98
98
  end
99
99
 
100
100
  def send_encrypted_messages(messages)
@@ -104,19 +104,19 @@ module MixinBot
104
104
  # http post request
105
105
  def send_encrypted_message(payload)
106
106
  path = '/encrypted_messages'
107
- payload = [payload] unless payload.is_a?(Array)
108
- access_token ||= access_token('POST', path, payload.to_json)
109
- authorization = format('Bearer %<access_token>s', access_token: access_token)
110
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
107
+ payload = [payload] if payload.is_a? Hash
108
+ raise ArgumentError, 'Wrong payload format!' unless payload.is_a? Array
109
+
110
+ client.post path, *payload
111
111
  end
112
112
 
113
- def encrypt_message(data, sessions = [], sk: nil, pk: nil)
113
+ def encrypt_message(data, sessions = [], sk: nil, pk: nil) # rubocop:disable Naming/MethodParameterName
114
114
  raise ArgumentError, 'Wrong sessions format!' unless sessions.all?(&->(s) { s.key?('session_id') && s.key?('public_key') })
115
115
 
116
- sk = private_key[0...32]
117
- pk ||= private_key[32...]
116
+ sk ||= config.session_private_key[0...32]
117
+ pk ||= config.session_private_key[32...]
118
118
 
119
- checksum = Digest::MD5.hexdigest sessions.map(&->(s) { s['session_id'] }).sort.join
119
+ Digest::MD5.hexdigest sessions.map(&->(s) { s['session_id'] }).sort.join
120
120
  encrypter = OpenSSL::Cipher.new('AES-128-GCM').encrypt
121
121
  key = encrypter.random_key
122
122
  nounce = encrypter.random_iv
@@ -128,14 +128,14 @@ module MixinBot
128
128
  bytes = [1]
129
129
  bytes += [sessions.size].pack('v*').bytes
130
130
  bytes += JOSE::JWA::Ed25519.pk_to_curve25519(pk).bytes
131
-
131
+
132
132
  sessions.each do |session|
133
133
  aes_key = JOSE::JWA::X25519.shared_secret(
134
134
  Base64.urlsafe_decode64(session['public_key']),
135
135
  JOSE::JWA::Ed25519.secret_to_curve25519(sk)
136
136
  )
137
137
 
138
- padding = 16 - key.size % 16
138
+ padding = 16 - (key.size % 16)
139
139
  padtext = ([padding] * padding).pack('C*')
140
140
 
141
141
  encrypter = OpenSSL::Cipher.new('AES-256-CBC').encrypt
@@ -143,7 +143,7 @@ module MixinBot
143
143
  iv = encrypter.random_iv
144
144
  encrypter.iv = iv
145
145
 
146
- bytes += (MixinBot::Utils::UUID.new(hex: session['session_id']).packed + iv).bytes
146
+ bytes += (MixinBot::UUID.new(hex: session['session_id']).packed + iv).bytes
147
147
  bytes += encrypter.update(key + padtext).bytes
148
148
  end
149
149
 
@@ -153,22 +153,22 @@ module MixinBot
153
153
  Base64.urlsafe_encode64 bytes.pack('C*'), padding: false
154
154
  end
155
155
 
156
- def decrypt_message(data, sk: nil, si: nil)
156
+ def decrypt_message(data, sk: nil, si: nil) # rubocop:disable Naming/MethodParameterName
157
157
  bytes = Base64.urlsafe_decode64(data).bytes
158
158
 
159
- si ||= session_id
160
- sk ||= private_key[0...32]
159
+ si ||= config.session_id
160
+ sk ||= config.session_private_key[0...32]
161
161
 
162
162
  size = 16 + 48
163
163
  return '' if bytes.size < 1 + 2 + 32 + size + 12
164
164
 
165
165
  session_length = bytes[1...3].pack('v*').unpack1('C*')
166
- prefix_size = 35 + session_length * size
166
+ prefix_size = 35 + (session_length * size)
167
167
 
168
168
  i = 35
169
169
  key = ''
170
170
  while i < prefix_size
171
- uuid = MixinBot::Utils::UUID.new(raw: bytes[i...(i + 16)].pack('C*')).unpacked
171
+ uuid = MixinBot::UUID.new(raw: bytes[i...(i + 16)].pack('C*')).unpacked
172
172
  if uuid == si
173
173
  pub = bytes[3...35]
174
174
  aes_key = JOSE::JWA::X25519.shared_secret(