1 package org
.asamk
.signal
.manager
.storage
;
3 import com
.zaxxer
.hikari
.HikariDataSource
;
5 import org
.asamk
.signal
.manager
.storage
.groups
.GroupStore
;
6 import org
.asamk
.signal
.manager
.storage
.identities
.IdentityKeyStore
;
7 import org
.asamk
.signal
.manager
.storage
.prekeys
.PreKeyStore
;
8 import org
.asamk
.signal
.manager
.storage
.prekeys
.SignedPreKeyStore
;
9 import org
.asamk
.signal
.manager
.storage
.recipients
.RecipientStore
;
10 import org
.asamk
.signal
.manager
.storage
.sendLog
.MessageSendLogStore
;
11 import org
.asamk
.signal
.manager
.storage
.senderKeys
.SenderKeyRecordStore
;
12 import org
.asamk
.signal
.manager
.storage
.senderKeys
.SenderKeySharedStore
;
13 import org
.asamk
.signal
.manager
.storage
.sessions
.SessionStore
;
14 import org
.asamk
.signal
.manager
.storage
.stickers
.StickerStore
;
15 import org
.slf4j
.Logger
;
16 import org
.slf4j
.LoggerFactory
;
19 import java
.sql
.Connection
;
20 import java
.sql
.SQLException
;
22 public class AccountDatabase
extends Database
{
24 private final static Logger logger
= LoggerFactory
.getLogger(AccountDatabase
.class);
25 private static final long DATABASE_VERSION
= 10;
27 private AccountDatabase(final HikariDataSource dataSource
) {
28 super(logger
, DATABASE_VERSION
, dataSource
);
31 public static AccountDatabase
init(File databaseFile
) throws SQLException
{
32 return initDatabase(databaseFile
, AccountDatabase
::new);
36 protected void createDatabase(final Connection connection
) throws SQLException
{
37 RecipientStore
.createSql(connection
);
38 MessageSendLogStore
.createSql(connection
);
39 StickerStore
.createSql(connection
);
40 PreKeyStore
.createSql(connection
);
41 SignedPreKeyStore
.createSql(connection
);
42 GroupStore
.createSql(connection
);
43 SessionStore
.createSql(connection
);
44 IdentityKeyStore
.createSql(connection
);
45 SenderKeyRecordStore
.createSql(connection
);
46 SenderKeySharedStore
.createSql(connection
);
50 protected void upgradeDatabase(final Connection connection
, final long oldVersion
) throws SQLException
{
52 logger
.debug("Updating database: Creating recipient table");
53 try (final var statement
= connection
.createStatement()) {
54 statement
.executeUpdate("""
55 CREATE TABLE recipient (
56 _id INTEGER PRIMARY KEY AUTOINCREMENT,
60 profile_key_credential BLOB,
66 expiration_time INTEGER NOT NULL DEFAULT 0,
67 blocked INTEGER NOT NULL DEFAULT FALSE,
68 archived INTEGER NOT NULL DEFAULT FALSE,
69 profile_sharing INTEGER NOT NULL DEFAULT FALSE,
71 profile_last_update_timestamp INTEGER NOT NULL DEFAULT 0,
72 profile_given_name TEXT,
73 profile_family_name TEXT,
75 profile_about_emoji TEXT,
76 profile_avatar_url_path TEXT,
77 profile_mobile_coin_address BLOB,
78 profile_unidentified_access_mode TEXT,
79 profile_capabilities TEXT
85 logger
.debug("Updating database: Creating sticker table");
86 try (final var statement
= connection
.createStatement()) {
87 statement
.executeUpdate("""
88 CREATE TABLE sticker (
89 _id INTEGER PRIMARY KEY,
90 pack_id BLOB UNIQUE NOT NULL,
91 pack_key BLOB NOT NULL,
92 installed INTEGER NOT NULL DEFAULT FALSE
98 logger
.debug("Updating database: Creating pre key tables");
99 try (final var statement
= connection
.createStatement()) {
100 statement
.executeUpdate("""
101 CREATE TABLE signed_pre_key (
102 _id INTEGER PRIMARY KEY,
103 account_id_type INTEGER NOT NULL,
104 key_id INTEGER NOT NULL,
105 public_key BLOB NOT NULL,
106 private_key BLOB NOT NULL,
107 signature BLOB NOT NULL,
108 timestamp INTEGER DEFAULT 0,
109 UNIQUE(account_id_type, key_id)
111 CREATE TABLE pre_key (
112 _id INTEGER PRIMARY KEY,
113 account_id_type INTEGER NOT NULL,
114 key_id INTEGER NOT NULL,
115 public_key BLOB NOT NULL,
116 private_key BLOB NOT NULL,
117 UNIQUE(account_id_type, key_id)
122 if (oldVersion
< 5) {
123 logger
.debug("Updating database: Creating group tables");
124 try (final var statement
= connection
.createStatement()) {
125 statement
.executeUpdate("""
126 CREATE TABLE group_v2 (
127 _id INTEGER PRIMARY KEY,
128 group_id BLOB UNIQUE NOT NULL,
129 master_key BLOB NOT NULL,
131 distribution_id BLOB UNIQUE NOT NULL,
132 blocked INTEGER NOT NULL DEFAULT FALSE,
133 permission_denied INTEGER NOT NULL DEFAULT FALSE
135 CREATE TABLE group_v1 (
136 _id INTEGER PRIMARY KEY,
137 group_id BLOB UNIQUE NOT NULL,
138 group_id_v2 BLOB UNIQUE,
141 expiration_time INTEGER NOT NULL DEFAULT 0,
142 blocked INTEGER NOT NULL DEFAULT FALSE,
143 archived INTEGER NOT NULL DEFAULT FALSE
145 CREATE TABLE group_v1_member (
146 _id INTEGER PRIMARY KEY,
147 group_id INTEGER NOT NULL REFERENCES group_v1 (_id) ON DELETE CASCADE,
148 recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
149 UNIQUE(group_id, recipient_id)
154 if (oldVersion
< 6) {
155 logger
.debug("Updating database: Creating session tables");
156 try (final var statement
= connection
.createStatement()) {
157 statement
.executeUpdate("""
158 CREATE TABLE session (
159 _id INTEGER PRIMARY KEY,
160 account_id_type INTEGER NOT NULL,
161 recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
162 device_id INTEGER NOT NULL,
163 record BLOB NOT NULL,
164 UNIQUE(account_id_type, recipient_id, device_id)
169 if (oldVersion
< 7) {
170 logger
.debug("Updating database: Creating identity table");
171 try (final var statement
= connection
.createStatement()) {
172 statement
.executeUpdate("""
173 CREATE TABLE identity (
174 _id INTEGER PRIMARY KEY,
175 recipient_id INTEGER UNIQUE NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
176 identity_key BLOB NOT NULL,
177 added_timestamp INTEGER NOT NULL,
178 trust_level INTEGER NOT NULL
183 if (oldVersion
< 8) {
184 logger
.debug("Updating database: Creating sender key tables");
185 try (final var statement
= connection
.createStatement()) {
186 statement
.executeUpdate("""
187 CREATE TABLE sender_key (
188 _id INTEGER PRIMARY KEY,
189 recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
190 device_id INTEGER NOT NULL,
191 distribution_id BLOB NOT NULL,
192 record BLOB NOT NULL,
193 created_timestamp INTEGER NOT NULL,
194 UNIQUE(recipient_id, device_id, distribution_id)
196 CREATE TABLE sender_key_shared (
197 _id INTEGER PRIMARY KEY,
198 recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
199 device_id INTEGER NOT NULL,
200 distribution_id BLOB NOT NULL,
201 timestamp INTEGER NOT NULL,
202 UNIQUE(recipient_id, device_id, distribution_id)
207 if (oldVersion
< 9) {
208 logger
.debug("Updating database: Adding urgent field");
209 try (final var statement
= connection
.createStatement()) {
210 statement
.executeUpdate("""
211 ALTER TABLE message_send_log_content ADD COLUMN urgent INTEGER NOT NULL DEFAULT TRUE;
215 if (oldVersion
< 10) {
216 logger
.debug("Updating database: Key tables on serviceId instead of recipientId");
217 try (final var statement
= connection
.createStatement()) {
218 statement
.executeUpdate("""
219 CREATE TABLE identity2 (
220 _id INTEGER PRIMARY KEY,
221 uuid BLOB UNIQUE NOT NULL,
222 identity_key BLOB NOT NULL,
223 added_timestamp INTEGER NOT NULL,
224 trust_level INTEGER NOT NULL
226 INSERT INTO identity2 (_id, uuid, identity_key, added_timestamp, trust_level)
227 SELECT i._id, r.uuid, i.identity_key, i.added_timestamp, i.trust_level
228 FROM identity i LEFT JOIN recipient r ON i.recipient_id = r._id
229 WHERE uuid IS NOT NULL;
231 ALTER TABLE identity2 RENAME TO identity;
233 DROP INDEX msl_recipient_index;
234 ALTER TABLE message_send_log ADD COLUMN uuid BLOB;
235 UPDATE message_send_log
237 FROM message_send_log i, (SELECT _id, uuid FROM recipient) AS r
238 WHERE i.recipient_id = r._id;
239 DELETE FROM message_send_log WHERE uuid IS NULL;
240 ALTER TABLE message_send_log DROP COLUMN recipient_id;
241 CREATE INDEX msl_recipient_index ON message_send_log (uuid, device_id, content_id);
243 CREATE TABLE sender_key2 (
244 _id INTEGER PRIMARY KEY,
246 device_id INTEGER NOT NULL,
247 distribution_id BLOB NOT NULL,
248 record BLOB NOT NULL,
249 created_timestamp INTEGER NOT NULL,
250 UNIQUE(uuid, device_id, distribution_id)
252 INSERT INTO sender_key2 (_id, uuid, device_id, distribution_id, record, created_timestamp)
253 SELECT s._id, r.uuid, s.device_id, s.distribution_id, s.record, s.created_timestamp
254 FROM sender_key s LEFT JOIN recipient r ON s.recipient_id = r._id
255 WHERE uuid IS NOT NULL;
256 DROP TABLE sender_key;
257 ALTER TABLE sender_key2 RENAME TO sender_key;
259 CREATE TABLE sender_key_shared2 (
260 _id INTEGER PRIMARY KEY,
262 device_id INTEGER NOT NULL,
263 distribution_id BLOB NOT NULL,
264 timestamp INTEGER NOT NULL,
265 UNIQUE(uuid, device_id, distribution_id)
267 INSERT INTO sender_key_shared2 (_id, uuid, device_id, distribution_id, timestamp)
268 SELECT s._id, r.uuid, s.device_id, s.distribution_id, s.timestamp
269 FROM sender_key_shared s LEFT JOIN recipient r ON s.recipient_id = r._id
270 WHERE uuid IS NOT NULL;
271 DROP TABLE sender_key_shared;
272 ALTER TABLE sender_key_shared2 RENAME TO sender_key_shared;
274 CREATE TABLE session2 (
275 _id INTEGER PRIMARY KEY,
276 account_id_type INTEGER NOT NULL,
278 device_id INTEGER NOT NULL,
279 record BLOB NOT NULL,
280 UNIQUE(account_id_type, uuid, device_id)
282 INSERT INTO session2 (_id, account_id_type, uuid, device_id, record)
283 SELECT s._id, s.account_id_type, r.uuid, s.device_id, s.record
284 FROM session s LEFT JOIN recipient r ON s.recipient_id = r._id
285 WHERE uuid IS NOT NULL;
287 ALTER TABLE session2 RENAME TO session;