Class: KStor::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/kstor/store.rb

Overview

Store and fetch objects in an SQLite database. rubocop:disable Metrics/MethodLength

Instance Method Summary collapse

Constructor Details

#initialize(file_path) ⇒ Store

Returns a new instance of Store.



11
12
13
14
15
# File 'lib/kstor/store.rb', line 11

def initialize(file_path)
  @file_path = file_path
  @db = SQLConnection.new(file_path)
  @cache = {}
end

Instance Method Details

#group_create(name, pubk) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/kstor/store.rb', line 70

def group_create(name, pubk)
  @db.execute(<<-EOSQL, name, pubk.to_s)
    INSERT INTO groups (name, pubk)
         VALUES (?, ?)
  EOSQL
  @db.last_insert_row_id
end

#groupsObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/kstor/store.rb', line 78

def groups
  return @cache[:groups] if @cache.key?(:groups)

  Log.debug('store: loading groups')
  rows = @db.execute(<<-EOSQL)
      SELECT id,
             name,
             pubk
        FROM groups
    ORDER BY name
  EOSQL
  @cache[:groups] = rows.to_h do |r|
    a = []
    a << r['id']
    a << Model::Group.new(
      id: r['id'], name: r['name'], pubk: Crypto::PublicKey.new(r['pubk'])
    )
    a
  end
end

#groups_for_secret(secret_id) ⇒ Object



245
246
247
248
249
250
251
252
253
# File 'lib/kstor/store.rb', line 245

def groups_for_secret(secret_id)
  Log.debug("store: loading group IDs for secret #{secret_id}")
  rows = @db.execute(<<-EOSQL, secret_id)
      SELECT group_id
        FROM secret_values
       WHERE secret_id = ?
  EOSQL
  rows.map { |r| r['group_id'] }
end

#keychain_item_create(user_id, group_id, encrypted_privk) ⇒ Object



63
64
65
66
67
68
# File 'lib/kstor/store.rb', line 63

def keychain_item_create(user_id, group_id, encrypted_privk)
  @db.execute(<<-EOSQL, user_id, group_id, encrypted_privk.to_s)
    INSERT INTO group_members (user_id, group_id, encrypted_privk)
         VALUES (?, ?, ?)
  EOSQL
end

#secret_create(author_id, encrypted_data) ⇒ Object

in:

- user ID
- hash of:
  - group ID
  - array of:
    - ciphertext
    - encrypted metadata

out: secret ID



232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/kstor/store.rb', line 232

def secret_create(author_id, encrypted_data)
  Log.debug("store: creating secret for user #{author_id}")
  @db.execute(<<-EOSQL, author_id, author_id)
    INSERT INTO secrets (value_author_id, meta_author_id) VALUES (?, ?)
  EOSQL
  secret_id = @db.last_insert_row_id
  encrypted_data.each do |group_id, (ciphertext, )|
    secret_value_create(secret_id, group_id, ciphertext, )
  end

  secret_id
end

#secret_delete(secret_id) ⇒ Object



287
288
289
290
291
292
293
# File 'lib/kstor/store.rb', line 287

def secret_delete(secret_id)
  Log.debug("store: delete secret ##{secret_id}")
  # Will cascade to secret_values:
  @db.execute(<<-EOSQL, secret_id)
    DELETE FROM secrets WHERE id = ?
  EOSQL
end

#secret_fetch(secret_id, user_id) ⇒ Object

in: secret ID, user ID out: encrypted value



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/kstor/store.rb', line 200

def secret_fetch(secret_id, user_id)
  Log.debug(
    "store: loading secret value ##{secret_id} for user ##{user_id}"
  )
  rows = @db.execute(<<-EOSQL, user_id, secret_id)
       SELECT s.id,
              s.value_author_id,
              s.meta_author_id,
              sv.group_id,
              sv.ciphertext,
              sv.encrypted_metadata
         FROM secrets s,
              secret_values sv,
              group_members gm
        WHERE gm.user_id = ?
          AND gm.group_id = sv.group_id
          AND sv.secret_id = ?
          AND s.id = sv.secret_id
  EOSQL
  return nil if rows.empty?

  secret_from_row(rows.first)
end

#secret_setmeta(secret_id, user_id, group_encrypted_metadata) ⇒ Object

in: secret ID, author ID, array of [group ID, encrypted_metadata] out: nil



257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/kstor/store.rb', line 257

def secret_setmeta(secret_id, user_id, )
  Log.debug("store: set metadata for secret ##{secret_id}")
  @db.execute(<<-EOSQL, user_id, secret_id)
    UPDATE secrets SET meta_author_id = ? WHERE id = ?
  EOSQL
  .each do |group_id, |
    @db.execute(<<-EOSQL, .to_s, secret_id, group_id)
      UPDATE secret_values
         SET encrypted_metadata = ?
       WHERE secret_id = ?
         AND group_id = ?
    EOSQL
  end
end

#secret_setvalue(secret_id, user_id, group_ciphertexts) ⇒ Object



272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/kstor/store.rb', line 272

def secret_setvalue(secret_id, user_id, group_ciphertexts)
  Log.debug("store: set value for secret ##{secret_id}")
  @db.execute(<<-EOSQL, user_id, secret_id)
    UPDATE secrets SET value_author_id = ? WHERE id = ?
  EOSQL
  group_ciphertexts.each do |group_id, ciphertext|
    @db.execute(<<-EOSQL, ciphertext.to_s, secret_id, group_id)
      UPDATE secret_values
         SET ciphertext = ?
       WHERE secret_id = ?
         AND group_id = ?
    EOSQL
  end
end

#secrets_for_user(user_id) ⇒ Object

in: user ID out: array of:

- secret ID
- group ID common between user and secret
- secret encrypted metadata
- secret value and metadata author IDs


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/kstor/store.rb', line 176

def secrets_for_user(user_id)
  Log.debug("store: loading secrets for user ##{user_id}")
  rows = @db.execute(<<-EOSQL, user_id)
       SELECT s.id,
              s.value_author_id,
              s.meta_author_id,
              sv.group_id,
              sv.ciphertext,
              sv.encrypted_metadata
         FROM secrets s,
              secret_values sv,
              group_members gm
        WHERE gm.user_id = ?
          AND gm.group_id = sv.group_id
          AND sv.secret_id = s.id
     GROUP BY s.id
     ORDER BY s.id, sv.group_id
  EOSQL

  rows.map { |r| secret_from_row(r) }
end

#transactionObject



17
18
19
# File 'lib/kstor/store.rb', line 17

def transaction(&)
  @db.transaction(&)
end

#user_by_id(user_id) ⇒ Object

in: user ID out:

- ID
- name
- status
- public key
- key derivation function parameters
- encrypted private key


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/kstor/store.rb', line 153

def user_by_id(user_id)
  Log.debug("store: loading user by ID ##{user_id}")
  rows = @db.execute(<<-EOSQL, user_id)
       SELECT u.id,
              u.login,
              u.name,
              u.status,
              c.kdf_params,
              c.pubk,
              c.encrypted_privk,
         FROM users u
    LEFT JOIN users_crypto_data c ON (c.user_id = u.id)
        WHERE u.id = ?
  EOSQL
  user_from_resultset(rows, include_crypto_data: true)
end

#user_by_login(login) ⇒ Object

in: login out:

- ID
- name
- status
- public key
- key derivation function parameters
- encrypted private key
- keychain: hash of:
  - group ID
  - encrypted group private key


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/kstor/store.rb', line 128

def ()
  Log.debug("store: loading user by login #{.inspect}")
  rows = @db.execute(<<-EOSQL, )
       SELECT u.id,
              u.login,
              u.name,
              u.status,
              c.kdf_params,
              c.pubk,
              c.encrypted_privk
         FROM users u
    LEFT JOIN users_crypto_data c ON (c.user_id = u.id)
        WHERE u.login = ?
  EOSQL
  user_from_resultset(rows, include_crypto_data: true)
end

#user_create(user) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/kstor/store.rb', line 29

def user_create(user)
  @db.execute(<<-EOSQL, user., user.name, 'new')
    INSERT INTO users (login, name, status)
         VALUES (?, ?, ?)
  EOSQL
  user.id = @db.last_insert_row_id
  Log.debug("store: stored new user #{user.}")
  params = [user.kdf_params, user.pubk, user.encrypted_privk].map(&:to_s)
  return user if params.any?(&:nil?)

  @db.execute(<<-EOSQL, user.id, *params)
    INSERT INTO users_crypto_data (user_id, kdf_params, pubk, encrypted_privk)
         VALUES (?, ?, ?, ?)
  EOSQL
  Log.debug("store: stored user crypto data for #{user.}")

  user
end

#user_update(user) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/kstor/store.rb', line 48

def user_update(user)
  @db.execute(<<-EOSQL, user.name, user.status, user.id)
    UPDATE users SET name = ?, status = ?
     WHERE id = ?
  EOSQL
  params = [user.kdf_params, user.pubk, user.encrypted_privk, user.id]
  @db.execute(<<-EOSQL, *params)
    UPDATE users_crypto_data SET
           kdf_params = ?,
           pubk = ?
           encrypted_params = ?
     WHERE user_id = ?
  EOSQL
end

#usersObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/kstor/store.rb', line 99

def users
  return @cache[:users] if @cache.key?(:users)

  Log.debug('store: loading users')
  rows = @db.execute(<<-EOSQL)
       SELECT u.id,
              u.login,
              u.name,
              u.status,
              c.pubk
         FROM users u
    LEFT JOIN users_crypto_data c ON (c.user_id = u.id)
     ORDER BY u.login
  EOSQL

  @cache[:users] = users_from_resultset(rows)
end

#users?Boolean

Returns:

  • (Boolean)


21
22
23
24
25
26
27
# File 'lib/kstor/store.rb', line 21

def users?
  rows = @db.execute('SELECT count(*) AS n FROM users')
  count = Integer(rows.first['n'])
  Log.debug("store: count of users is #{count}")

  count.positive?
end