async-matrix 1.1.0 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 194e89bd46e36b9d5dda162d92386d360044984341effd4bc1b4012e3fe30001
4
- data.tar.gz: 223ce9eb16f32334ec2817fb5dbf8ea234dc73b7c668246a8408c26012f1df3d
3
+ metadata.gz: '044956d2cd8c29c0875733a8245ad009d61dfa59efcfcb7556ba24605f4aa073'
4
+ data.tar.gz: 917fb89e79e7ae68dc590ae287b612e5e940351601af5532ac2c7b93dafb1a42
5
5
  SHA512:
6
- metadata.gz: 1fac9d4cf9e5bdbff4817c7924e92160edf5f5f8dfbeee6ccc6080b3a03927e17e81c7f03671069f09a6b064ccd2fe3dada2f663c05c0bb1c2e3b98f1e74bb99
7
- data.tar.gz: f5dde0ffde70897beedae255b1e7ece7b4e753036006a119d8b747d0e5a279938b7080e59b455d7a9e20518dcaa6e271629dee29302bc9995daac5c45cef9c8f
6
+ metadata.gz: 2044815f830d6f47e958a322fe09fad2773a07146d6dd39f5b5474d5c48f8f46a2a96e6c5fa6ebf38d4c11cbf57a305fcdb3ced1e55873d21fd3eff507dc1041
7
+ data.tar.gz: a1304c33ff1bd07ddf11965ef98f65495a4458b45ec346dff23e0881ed30327009de1fc4cdfee0b1806b384ca0d61893f1efdbeaa657d732a489b32614704d4b
@@ -0,0 +1,26 @@
1
+ [package]
2
+ name = "async_matrix_e2ee"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ publish = false
6
+
7
+ [lib]
8
+ name = "async_matrix_e2ee"
9
+ crate-type = ["cdylib"]
10
+
11
+ [dependencies]
12
+ magnus = "0.7"
13
+
14
+ # vodozemac 0.10.0 (2026-04-13), default features (libolm-compat).
15
+ #
16
+ # - 0.10 is the release that fixes the all-zero / non-contributory DH issue from
17
+ # Soatok's review (the proposed patch was deprecated `since = "0.10.0"`), so we
18
+ # pin >= 0.10 rather than 0.9.
19
+ # - There is no `strict-signatures` feature in 0.10 (it existed pre-0.10; the
20
+ # related signature-verification hardening was resolved upstream).
21
+ # - There is no `fuzzing` Cargo feature: vodozemac's MAC/signature bypass is
22
+ # gated behind `#[cfg(fuzzing)]`, only set by `cargo fuzz`
23
+ # (RUSTFLAGS=--cfg fuzzing). A normal `cargo build`/`rake compile` never
24
+ # enables it. Never build production artifacts with `cargo fuzz`.
25
+ [dependencies.vodozemac]
26
+ version = "0.10"
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "rb_sys/mkmf"
5
+
6
+ # Builds the Rust crate in this directory and produces async_matrix_e2ee.so.
7
+ # The crate's #[magnus::init] defines the classes under Async::Matrix::E2EE.
8
+ create_rust_makefile("async_matrix_e2ee")
@@ -0,0 +1,326 @@
1
+ //! Ruby bindings for vodozemac (Matrix Olm/Megolm), via magnus.
2
+ //!
3
+ //! This is the Ruby analogue of matrix-nio/vodozemac-python (which uses PyO3).
4
+ //! It exposes vodozemac's Account / Session (Olm) and GroupSession /
5
+ //! InboundGroupSession (Megolm) under the `Async::Matrix::E2EE` module.
6
+ //!
7
+ //! The API is deliberately base64-string / integer centric rather than passing
8
+ //! wrapped key objects around: Matrix moves keys and ciphertext as base64
9
+ //! strings inside JSON, so a string API drops straight into the protocol layer
10
+ //! and keeps the magnus surface small.
11
+
12
+ use std::cell::RefCell;
13
+ use std::collections::HashMap;
14
+
15
+ use magnus::{function, method, prelude::*, Error, Ruby};
16
+
17
+ use vodozemac::{base64_decode, base64_encode, Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature};
18
+ use vodozemac::olm::{
19
+ Account as OlmAccount, AccountPickle, OlmMessage, PreKeyMessage, Session as OlmSession,
20
+ SessionConfig as OlmSessionConfig, SessionPickle,
21
+ };
22
+ use vodozemac::megolm::{
23
+ GroupSession as MegolmGroupSession, GroupSessionPickle, InboundGroupSession as MegolmInbound,
24
+ InboundGroupSessionPickle, MegolmMessage, SessionConfig as MegolmSessionConfig, SessionKey,
25
+ };
26
+
27
+ // --- helpers ---------------------------------------------------------------
28
+
29
+ fn rt_err<E: std::fmt::Display>(e: E) -> Error {
30
+ Error::new(magnus::exception::runtime_error(), e.to_string())
31
+ }
32
+
33
+ fn key32(label: &str, bytes: &[u8]) -> Result<[u8; 32], Error> {
34
+ bytes
35
+ .try_into()
36
+ .map_err(|_| rt_err(format!("{label} must be 32 bytes, got {}", bytes.len())))
37
+ }
38
+
39
+ // --- Account ---------------------------------------------------------------
40
+
41
+ #[magnus::wrap(class = "Async::Matrix::E2EE::Account", free_immediately, size)]
42
+ struct Account(RefCell<OlmAccount>);
43
+
44
+ impl Account {
45
+ fn new() -> Self {
46
+ Account(RefCell::new(OlmAccount::new()))
47
+ }
48
+
49
+ fn from_pickle(pickle: String, pickle_key: String) -> Result<Self, Error> {
50
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
51
+ let p = AccountPickle::from_encrypted(&pickle, &key).map_err(rt_err)?;
52
+ Ok(Account(RefCell::new(OlmAccount::from_pickle(p))))
53
+ }
54
+
55
+ fn pickle(&self, pickle_key: String) -> Result<String, Error> {
56
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
57
+ Ok(self.0.borrow().pickle().encrypt(&key))
58
+ }
59
+
60
+ fn ed25519_key(&self) -> String {
61
+ self.0.borrow().ed25519_key().to_base64()
62
+ }
63
+
64
+ fn curve25519_key(&self) -> String {
65
+ self.0.borrow().curve25519_key().to_base64()
66
+ }
67
+
68
+ fn sign(&self, message: String) -> String {
69
+ self.0.borrow().sign(message.as_bytes()).to_base64()
70
+ }
71
+
72
+ fn one_time_keys(&self) -> HashMap<String, String> {
73
+ self.0
74
+ .borrow()
75
+ .one_time_keys()
76
+ .into_iter()
77
+ .map(|(k, v)| (k.to_base64(), v.to_base64()))
78
+ .collect()
79
+ }
80
+
81
+ fn max_number_of_one_time_keys(&self) -> usize {
82
+ self.0.borrow().max_number_of_one_time_keys()
83
+ }
84
+
85
+ fn generate_one_time_keys(&self, count: usize) {
86
+ self.0.borrow_mut().generate_one_time_keys(count);
87
+ }
88
+
89
+ fn fallback_key(&self) -> HashMap<String, String> {
90
+ self.0
91
+ .borrow()
92
+ .fallback_key()
93
+ .into_iter()
94
+ .map(|(k, v)| (k.to_base64(), v.to_base64()))
95
+ .collect()
96
+ }
97
+
98
+ fn generate_fallback_key(&self) {
99
+ self.0.borrow_mut().generate_fallback_key();
100
+ }
101
+
102
+ fn mark_keys_as_published(&self) {
103
+ self.0.borrow_mut().mark_keys_as_published();
104
+ }
105
+
106
+ /// Returns a Session for sending to a peer identified by their identity and
107
+ /// one-time keys (both base64).
108
+ fn create_outbound_session(
109
+ &self,
110
+ identity_key: String,
111
+ one_time_key: String,
112
+ ) -> Result<Session, Error> {
113
+ let ik = Curve25519PublicKey::from_base64(&identity_key).map_err(rt_err)?;
114
+ let otk = Curve25519PublicKey::from_base64(&one_time_key).map_err(rt_err)?;
115
+ let session = self
116
+ .0
117
+ .borrow()
118
+ .create_outbound_session(OlmSessionConfig::version_1(), ik, otk)
119
+ .map_err(rt_err)?;
120
+ Ok(Session(RefCell::new(session)))
121
+ }
122
+
123
+ /// Establishes an inbound Session from a received pre-key message (base64
124
+ /// body, as carried in an m.room.encrypted olm `body`). Returns
125
+ /// `[session, plaintext]`.
126
+ fn create_inbound_session(
127
+ &self,
128
+ identity_key: String,
129
+ prekey_message_body: String,
130
+ ) -> Result<(Session, String), Error> {
131
+ let ik = Curve25519PublicKey::from_base64(&identity_key).map_err(rt_err)?;
132
+ let prekey = PreKeyMessage::from_base64(&prekey_message_body).map_err(rt_err)?;
133
+ let result = self
134
+ .0
135
+ .borrow_mut()
136
+ .create_inbound_session(OlmSessionConfig::version_1(), ik, &prekey)
137
+ .map_err(rt_err)?;
138
+ let plaintext = String::from_utf8(result.plaintext).map_err(rt_err)?;
139
+ Ok((Session(RefCell::new(result.session)), plaintext))
140
+ }
141
+ }
142
+
143
+ // --- Session (Olm 1:1) -----------------------------------------------------
144
+
145
+ #[magnus::wrap(class = "Async::Matrix::E2EE::Session", free_immediately, size)]
146
+ struct Session(RefCell<OlmSession>);
147
+
148
+ impl Session {
149
+ fn session_id(&self) -> String {
150
+ self.0.borrow().session_id()
151
+ }
152
+
153
+ fn pickle(&self, pickle_key: String) -> Result<String, Error> {
154
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
155
+ Ok(self.0.borrow().pickle().encrypt(&key))
156
+ }
157
+
158
+ fn from_pickle(pickle: String, pickle_key: String) -> Result<Self, Error> {
159
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
160
+ let p = SessionPickle::from_encrypted(&pickle, &key).map_err(rt_err)?;
161
+ Ok(Session(RefCell::new(OlmSession::from_pickle(p))))
162
+ }
163
+
164
+ /// Encrypts plaintext; returns `[message_type, body_base64]` matching the
165
+ /// Matrix olm ciphertext shape.
166
+ fn encrypt(&self, plaintext: String) -> Result<(usize, String), Error> {
167
+ let message = self.0.borrow_mut().encrypt(plaintext.as_bytes()).map_err(rt_err)?;
168
+ let (mtype, ciphertext) = message.to_parts();
169
+ Ok((mtype, base64_encode(ciphertext)))
170
+ }
171
+
172
+ /// Decrypts an olm message given its type (0 = pre-key, 1 = normal) and
173
+ /// base64 body.
174
+ fn decrypt(&self, message_type: usize, body: String) -> Result<String, Error> {
175
+ let ciphertext = base64_decode(&body).map_err(rt_err)?;
176
+ let message = OlmMessage::from_parts(message_type, &ciphertext).map_err(rt_err)?;
177
+ let plaintext = self.0.borrow_mut().decrypt(&message).map_err(rt_err)?;
178
+ String::from_utf8(plaintext).map_err(rt_err)
179
+ }
180
+ }
181
+
182
+ // --- GroupSession (Megolm outbound) ---------------------------------------
183
+
184
+ #[magnus::wrap(class = "Async::Matrix::E2EE::GroupSession", free_immediately, size)]
185
+ struct GroupSession(RefCell<MegolmGroupSession>);
186
+
187
+ impl GroupSession {
188
+ fn new() -> Self {
189
+ GroupSession(RefCell::new(MegolmGroupSession::new(MegolmSessionConfig::version_1())))
190
+ }
191
+
192
+ fn session_id(&self) -> String {
193
+ self.0.borrow().session_id()
194
+ }
195
+
196
+ fn message_index(&self) -> u32 {
197
+ self.0.borrow().message_index()
198
+ }
199
+
200
+ /// The session key (base64) to share with recipients via m.room_key.
201
+ fn session_key(&self) -> String {
202
+ self.0.borrow().session_key().to_base64()
203
+ }
204
+
205
+ /// Encrypts plaintext, returning the megolm message as base64.
206
+ fn encrypt(&self, plaintext: String) -> String {
207
+ self.0.borrow_mut().encrypt(plaintext.as_bytes()).to_base64()
208
+ }
209
+
210
+ fn pickle(&self, pickle_key: String) -> Result<String, Error> {
211
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
212
+ Ok(self.0.borrow().pickle().encrypt(&key))
213
+ }
214
+
215
+ fn from_pickle(pickle: String, pickle_key: String) -> Result<Self, Error> {
216
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
217
+ let p = GroupSessionPickle::from_encrypted(&pickle, &key).map_err(rt_err)?;
218
+ Ok(GroupSession(RefCell::new(MegolmGroupSession::from_pickle(p))))
219
+ }
220
+ }
221
+
222
+ // --- InboundGroupSession (Megolm inbound) ---------------------------------
223
+
224
+ #[magnus::wrap(class = "Async::Matrix::E2EE::InboundGroupSession", free_immediately, size)]
225
+ struct InboundGroupSession(RefCell<MegolmInbound>);
226
+
227
+ impl InboundGroupSession {
228
+ /// Build from a base64 session key received in an m.room_key event.
229
+ fn new(session_key: String) -> Result<Self, Error> {
230
+ let key = SessionKey::from_base64(&session_key).map_err(rt_err)?;
231
+ Ok(InboundGroupSession(RefCell::new(MegolmInbound::new(
232
+ &key,
233
+ MegolmSessionConfig::version_1(),
234
+ ))))
235
+ }
236
+
237
+ fn session_id(&self) -> String {
238
+ self.0.borrow().session_id()
239
+ }
240
+
241
+ fn first_known_index(&self) -> u32 {
242
+ self.0.borrow().first_known_index()
243
+ }
244
+
245
+ /// Decrypts a base64 megolm message; returns `[plaintext, message_index]`.
246
+ fn decrypt(&self, message: String) -> Result<(String, u32), Error> {
247
+ let msg = MegolmMessage::from_base64(&message).map_err(rt_err)?;
248
+ let decrypted = self.0.borrow_mut().decrypt(&msg).map_err(rt_err)?;
249
+ let plaintext = String::from_utf8(decrypted.plaintext).map_err(rt_err)?;
250
+ Ok((plaintext, decrypted.message_index))
251
+ }
252
+
253
+ fn pickle(&self, pickle_key: String) -> Result<String, Error> {
254
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
255
+ Ok(self.0.borrow().pickle().encrypt(&key))
256
+ }
257
+
258
+ fn from_pickle(pickle: String, pickle_key: String) -> Result<Self, Error> {
259
+ let key = key32("pickle_key", pickle_key.as_bytes())?;
260
+ let p = InboundGroupSessionPickle::from_encrypted(&pickle, &key).map_err(rt_err)?;
261
+ Ok(InboundGroupSession(RefCell::new(MegolmInbound::from_pickle(p))))
262
+ }
263
+ }
264
+
265
+ // --- module-level functions ------------------------------------------------
266
+
267
+ /// Verify an ed25519 signature. `key` and `signature` are base64; returns bool.
268
+ fn verify_signature(key: String, message: String, signature: String) -> Result<bool, Error> {
269
+ let public_key = Ed25519PublicKey::from_base64(&key).map_err(rt_err)?;
270
+ let sig = Ed25519Signature::from_base64(&signature).map_err(rt_err)?;
271
+ Ok(public_key.verify(message.as_bytes(), &sig).is_ok())
272
+ }
273
+
274
+ // --- init ------------------------------------------------------------------
275
+
276
+ #[magnus::init]
277
+ fn init(ruby: &Ruby) -> Result<(), Error> {
278
+ let namespace = ruby.define_module("Async")?.define_module("Matrix")?.define_module("E2EE")?;
279
+
280
+ let account = namespace.define_class("Account", ruby.class_object())?;
281
+ account.define_singleton_method("new", function!(Account::new, 0))?;
282
+ account.define_singleton_method("from_pickle", function!(Account::from_pickle, 2))?;
283
+ account.define_method("pickle", method!(Account::pickle, 1))?;
284
+ account.define_method("ed25519_key", method!(Account::ed25519_key, 0))?;
285
+ account.define_method("curve25519_key", method!(Account::curve25519_key, 0))?;
286
+ account.define_method("sign", method!(Account::sign, 1))?;
287
+ account.define_method("one_time_keys", method!(Account::one_time_keys, 0))?;
288
+ account.define_method(
289
+ "max_number_of_one_time_keys",
290
+ method!(Account::max_number_of_one_time_keys, 0),
291
+ )?;
292
+ account.define_method("generate_one_time_keys", method!(Account::generate_one_time_keys, 1))?;
293
+ account.define_method("fallback_key", method!(Account::fallback_key, 0))?;
294
+ account.define_method("generate_fallback_key", method!(Account::generate_fallback_key, 0))?;
295
+ account.define_method("mark_keys_as_published", method!(Account::mark_keys_as_published, 0))?;
296
+ account.define_method("create_outbound_session", method!(Account::create_outbound_session, 2))?;
297
+ account.define_method("create_inbound_session", method!(Account::create_inbound_session, 2))?;
298
+
299
+ let session = namespace.define_class("Session", ruby.class_object())?;
300
+ session.define_singleton_method("from_pickle", function!(Session::from_pickle, 2))?;
301
+ session.define_method("session_id", method!(Session::session_id, 0))?;
302
+ session.define_method("pickle", method!(Session::pickle, 1))?;
303
+ session.define_method("encrypt", method!(Session::encrypt, 1))?;
304
+ session.define_method("decrypt", method!(Session::decrypt, 2))?;
305
+
306
+ let group = namespace.define_class("GroupSession", ruby.class_object())?;
307
+ group.define_singleton_method("new", function!(GroupSession::new, 0))?;
308
+ group.define_singleton_method("from_pickle", function!(GroupSession::from_pickle, 2))?;
309
+ group.define_method("session_id", method!(GroupSession::session_id, 0))?;
310
+ group.define_method("message_index", method!(GroupSession::message_index, 0))?;
311
+ group.define_method("session_key", method!(GroupSession::session_key, 0))?;
312
+ group.define_method("encrypt", method!(GroupSession::encrypt, 1))?;
313
+ group.define_method("pickle", method!(GroupSession::pickle, 1))?;
314
+
315
+ let inbound = namespace.define_class("InboundGroupSession", ruby.class_object())?;
316
+ inbound.define_singleton_method("new", function!(InboundGroupSession::new, 1))?;
317
+ inbound.define_singleton_method("from_pickle", function!(InboundGroupSession::from_pickle, 2))?;
318
+ inbound.define_method("session_id", method!(InboundGroupSession::session_id, 0))?;
319
+ inbound.define_method("first_known_index", method!(InboundGroupSession::first_known_index, 0))?;
320
+ inbound.define_method("decrypt", method!(InboundGroupSession::decrypt, 1))?;
321
+ inbound.define_method("pickle", method!(InboundGroupSession::pickle, 1))?;
322
+
323
+ namespace.define_module_function("verify_signature", function!(verify_signature, 3))?;
324
+
325
+ Ok(())
326
+ }
@@ -132,11 +132,12 @@ module Async
132
132
 
133
133
  path = "/" + segments.map { |s| _encode(s) }.join("/")
134
134
 
135
+ if query && !query.empty?
136
+ qs = query.map { |k, v| "#{_encode(k.to_s)}=#{_encode(v.to_s)}" }.join("&")
137
+ path = "#{path}?#{qs}"
138
+ end
139
+
135
140
  if _binary_route?(segments)
136
- if query && !query.empty?
137
- qs = query.map { |k, v| "#{_encode(k.to_s)}=#{_encode(v.to_s)}" }.join("&")
138
- path = "#{path}?#{qs}"
139
- end
140
141
  case method
141
142
  when "GET"
142
143
  @client.media_client.download(path)
@@ -149,10 +150,6 @@ module Async
149
150
  retry_opts = max_retries ? {max_retries: max_retries} : {}
150
151
  case method
151
152
  when "GET"
152
- if query && !query.empty?
153
- qs = query.map { |k, v| "#{_encode(k.to_s)}=#{_encode(v.to_s)}" }.join("&")
154
- path = "#{path}?#{qs}"
155
- end
156
153
  @client.get(path, **retry_opts)
157
154
  when "POST"
158
155
  @client.post(path, body || {}, **retry_opts)
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Loads the native vodozemac binding (ext/async_matrix_e2ee) and namespaces the
7
+ # Olm/Megolm primitives under Async::Matrix::E2EE.
8
+ #
9
+ # The native classes (Account, Session, GroupSession, InboundGroupSession) and
10
+ # the module function verify_signature are defined by the Rust #[magnus::init].
11
+ # This file only locates and requires the compiled object.
12
+ #
13
+ # account = Async::Matrix::E2EE::Account.new
14
+ # account.curve25519_key # => base64 string
15
+ # group = Async::Matrix::E2EE::GroupSession.new
16
+ # msg = group.encrypt("hello") # => base64 megolm message
17
+ # inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
18
+ # inbound.decrypt(msg) # => ["hello", 0]
19
+
20
+ module Async
21
+ module Matrix
22
+ module E2EE
23
+ end
24
+ end
25
+ end
26
+
27
+ # rake-compiler installs the shared object alongside this file.
28
+ require_relative "async_matrix_e2ee"
29
+
30
+ test do
31
+ describe "Async::Matrix::E2EE" do
32
+ it "exposes account identity keys as base64" do
33
+ account = Async::Matrix::E2EE::Account.new
34
+ account.curve25519_key.should.be.kind_of String
35
+ account.ed25519_key.should.be.kind_of String
36
+ account.curve25519_key.length.should.be > 0
37
+ end
38
+
39
+ it "round-trips a megolm group message" do
40
+ group = Async::Matrix::E2EE::GroupSession.new
41
+ inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
42
+
43
+ message = group.encrypt("hello world")
44
+ plaintext, index = inbound.decrypt(message)
45
+
46
+ plaintext.should == "hello world"
47
+ index.should == 0
48
+ inbound.session_id.should == group.session_id
49
+ end
50
+
51
+ it "round-trips an olm 1:1 message" do
52
+ alice = Async::Matrix::E2EE::Account.new
53
+ bob = Async::Matrix::E2EE::Account.new
54
+ bob.generate_one_time_keys(1)
55
+ bob_otk = bob.one_time_keys.values.first
56
+
57
+ outbound = alice.create_outbound_session(bob.curve25519_key, bob_otk)
58
+ type, body = outbound.encrypt("yo g")
59
+ type.should == 0 # pre-key message
60
+
61
+ session, plaintext = bob.create_inbound_session(alice.curve25519_key, body)
62
+ plaintext.should == "yo g"
63
+
64
+ reply_type, reply_body = session.encrypt("hello back")
65
+ outbound.decrypt(reply_type, reply_body).should == "hello back"
66
+ end
67
+
68
+ it "verifies a valid ed25519 signature and rejects a bad one" do
69
+ account = Async::Matrix::E2EE::Account.new
70
+ signature = account.sign("payload")
71
+
72
+ Async::Matrix::E2EE.verify_signature(account.ed25519_key, "payload", signature).should == true
73
+ Async::Matrix::E2EE.verify_signature(account.ed25519_key, "tampered", signature).should == false
74
+ end
75
+
76
+ it "survives a pickle round-trip" do
77
+ key = "0" * 32
78
+ group = Async::Matrix::E2EE::GroupSession.new
79
+ pickled = group.pickle(key)
80
+
81
+ restored = Async::Matrix::E2EE::GroupSession.from_pickle(pickled, key)
82
+ restored.session_id.should == group.session_id
83
+ end
84
+ end
85
+ end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module Matrix
8
- VERSION = "1.1.0"
8
+ VERSION = "1.2.0"
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-matrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Kidd
@@ -107,6 +107,20 @@ dependencies:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
109
  version: '1.2'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rb_sys
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.9'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.9'
110
124
  - !ruby/object:Gem::Dependency
111
125
  name: falcon
112
126
  requirement: !ruby/object:Gem::Requirement
@@ -149,12 +163,27 @@ dependencies:
149
163
  - - ">="
150
164
  - !ruby/object:Gem::Version
151
165
  version: '0'
166
+ - !ruby/object:Gem::Dependency
167
+ name: rake-compiler
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '1.2'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.2'
152
180
  description: Async-native Matrix protocol primitives built on the Socketry async ecosystem.
153
181
  Provides well-known discovery, event notification, and application service models.
154
182
  email:
155
183
  - nathankidd@hey.com
156
184
  executables: []
157
- extensions: []
185
+ extensions:
186
+ - ext/async_matrix_e2ee/extconf.rb
158
187
  extra_rdoc_files: []
159
188
  files:
160
189
  - LICENSE
@@ -455,6 +484,9 @@ files:
455
484
  - data/matrix-spec/event-schemas/schema/m.sticker.yaml
456
485
  - data/matrix-spec/event-schemas/schema/m.tag.yaml
457
486
  - data/matrix-spec/event-schemas/schema/m.typing.yaml
487
+ - ext/async_matrix_e2ee/Cargo.toml
488
+ - ext/async_matrix_e2ee/extconf.rb
489
+ - ext/async_matrix_e2ee/src/lib.rs
458
490
  - lib/async/discord.rb
459
491
  - lib/async/discord/api.rb
460
492
  - lib/async/discord/api/path_tree.rb
@@ -511,6 +543,7 @@ files:
511
543
  - lib/async/matrix/client.rb
512
544
  - lib/async/matrix/connection.rb
513
545
  - lib/async/matrix/double_puppet_client.rb
546
+ - lib/async/matrix/e2ee.rb
514
547
  - lib/async/matrix/endpoint.rb
515
548
  - lib/async/matrix/error.rb
516
549
  - lib/async/matrix/media_client.rb