From 185eb8bdddf29bceced33e25dbfadc5ce19cb936 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sun, 12 Jan 2025 18:45:35 +0100 Subject: [PATCH] caldav: Implement Dav Push topic --- ...2528416036e401f75a03100b6bfbee687b978520.json | 12 ++++++++++++ ...cf9780e4f32af800dfb75d1442f3e68dd3412de.json} | 12 +++++++++--- ...d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6.json | 12 ------------ ...9d77a6f509d868de28d5b2b3724d66059223aaa.json} | 6 +++--- ...aed24c0185ce3b1bc39fd0eab7426f581aafe02.json} | 6 +++--- ...9df445ac48f7e438f1d99519dad49a127399971.json} | 12 +++++++++--- ...810bbbb203bab874860aa05eb311259e4baaf05.json} | 12 +++++++++--- ...e558fde44fcbd4f7d27c283658de38330bef095.json} | 12 +++++++++--- ...5134b804579ad4300fd8227b0d6f307281f25111.json | 12 ++++++++++++ ...db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b.json} | 12 +++++++++--- ...df054f2fbb9bedea0ec2a0f06ed25d30a02338d3.json | 12 ------------ ...c745f76d3799958d929e8e8d16aa3ceff98e72d.json} | 12 +++++++++--- Cargo.lock | 3 +++ Cargo.toml | 2 +- crates/caldav/Cargo.toml | 1 + crates/caldav/src/calendar/methods/mkcalendar.rs | 1 + crates/caldav/src/calendar/resource.rs | 15 +-------------- crates/carddav/Cargo.toml | 1 + crates/carddav/src/addressbook/methods/mkcol.rs | 1 + crates/store/src/addressbook/addressbook.rs | 1 + crates/store/src/calendar/calendar.rs | 1 + crates/store/src/contact_birthday_store.rs | 7 +++++++ crates/store_sqlite/migrations/1_calendar.sql | 1 + crates/store_sqlite/migrations/2_addressbook.sql | 1 + crates/store_sqlite/src/addressbook_store.rs | 14 ++++++++------ crates/store_sqlite/src/calendar_store.rs | 16 +++++++++------- 26 files changed, 121 insertions(+), 76 deletions(-) create mode 100644 .sqlx/query-16a7e0cb4527060339c168ee2528416036e401f75a03100b6bfbee687b978520.json rename .sqlx/{query-a74288844bf11fd318c3e688d3a4bc454d8b162d7afbeebfc448211990cd8823.json => query-23bc337c3f74466be1d136218cf9780e4f32af800dfb75d1442f3e68dd3412de.json} (82%) delete mode 100644 .sqlx/query-32969555ebbf5d7220c1c0d2d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6.json rename .sqlx/{query-0d0bd23849e3e9492531fa8ce0eb22832d0c16d690cebbcb7e546cab3e942d64.json => query-3ad4ff83b0317ee316f6e6d589d77a6f509d868de28d5b2b3724d66059223aaa.json} (57%) rename .sqlx/{query-51313b93f21cef5b82eb1b5a583940a6f74ba19fbf717f4d6f7351cdae4def0d.json => query-508adcac37e0d6751924f65e9aed24c0185ce3b1bc39fd0eab7426f581aafe02.json} (52%) rename .sqlx/{query-24ece624823b418fa96a867f57d62ed755035e88b0d9363b71aac8aedff1cbb6.json => query-6d32ecdc8dbd73ba917f2e5f89df445ac48f7e438f1d99519dad49a127399971.json} (82%) rename .sqlx/{query-65c6f1c6c3e7d587f3f9a126260a0e12c5d372c754ddaf0d2a1d7b65e0119799.json => query-9be5d6df7d30a9a85aece59be810bbbb203bab874860aa05eb311259e4baaf05.json} (72%) rename .sqlx/{query-9770a3a1c85aa92e7787ede67e86aa680e0831613cc9cb87cb19928fc538d35c.json => query-ad596abc6b3826251bdf640ece558fde44fcbd4f7d27c283658de38330bef095.json} (81%) create mode 100644 .sqlx/query-c0d889d0738797185b10ec3e5134b804579ad4300fd8227b0d6f307281f25111.json rename .sqlx/{query-d1dd991de4ba20fd7940ae0dbe5d6c1298ed928adbf51e2fcacd060b518786c7.json => query-c736a652873a4795bb7a9bd96db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b.json} (73%) delete mode 100644 .sqlx/query-d8a41068baadd14fd412d2cbdf054f2fbb9bedea0ec2a0f06ed25d30a02338d3.json rename .sqlx/{query-34e911d0f7f176cbd66ed6eb1cad7b2eb5b87acccfe9a69b1dcce05c1c303705.json => query-e5ded4814aae1fc033bb90d27c745f76d3799958d929e8e8d16aa3ceff98e72d.json} (72%) diff --git a/.sqlx/query-16a7e0cb4527060339c168ee2528416036e401f75a03100b6bfbee687b978520.json b/.sqlx/query-16a7e0cb4527060339c168ee2528416036e401f75a03100b6bfbee687b978520.json new file mode 100644 index 0000000..6276abe --- /dev/null +++ b/.sqlx/query-16a7e0cb4527060339c168ee2528416036e401f75a03100b6bfbee687b978520.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE addressbooks SET principal = ?, id = ?, displayname = ?, description = ?, push_topic = ?\n WHERE (principal, id) = (?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 7 + }, + "nullable": [] + }, + "hash": "16a7e0cb4527060339c168ee2528416036e401f75a03100b6bfbee687b978520" +} diff --git a/.sqlx/query-a74288844bf11fd318c3e688d3a4bc454d8b162d7afbeebfc448211990cd8823.json b/.sqlx/query-23bc337c3f74466be1d136218cf9780e4f32af800dfb75d1442f3e68dd3412de.json similarity index 82% rename from .sqlx/query-a74288844bf11fd318c3e688d3a4bc454d8b162d7afbeebfc448211990cd8823.json rename to .sqlx/query-23bc337c3f74466be1d136218cf9780e4f32af800dfb75d1442f3e68dd3412de.json index 5d24d85..50d080e 100644 --- a/.sqlx/query-a74288844bf11fd318c3e688d3a4bc454d8b162d7afbeebfc448211990cd8823.json +++ b/.sqlx/query-23bc337c3f74466be1d136218cf9780e4f32af800dfb75d1442f3e68dd3412de.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, \"order\", displayname, description, color, timezone, timezone_id, deleted_at, subscription_url\n FROM calendars\n WHERE (principal, id) = (?, ?)", + "query": "SELECT principal, id, synctoken, \"order\", displayname, description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic\n FROM calendars\n WHERE (principal, id) = (?, ?)", "describe": { "columns": [ { @@ -57,6 +57,11 @@ "name": "subscription_url", "ordinal": 10, "type_info": "Text" + }, + { + "name": "push_topic", + "ordinal": 11, + "type_info": "Text" } ], "parameters": { @@ -73,8 +78,9 @@ true, true, true, - true + true, + false ] }, - "hash": "a74288844bf11fd318c3e688d3a4bc454d8b162d7afbeebfc448211990cd8823" + "hash": "23bc337c3f74466be1d136218cf9780e4f32af800dfb75d1442f3e68dd3412de" } diff --git a/.sqlx/query-32969555ebbf5d7220c1c0d2d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6.json b/.sqlx/query-32969555ebbf5d7220c1c0d2d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6.json deleted file mode 100644 index 42098de..0000000 --- a/.sqlx/query-32969555ebbf5d7220c1c0d2d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO calendars (principal, id, displayname, description, \"order\", color, timezone, timezone_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - "describe": { - "columns": [], - "parameters": { - "Right": 8 - }, - "nullable": [] - }, - "hash": "32969555ebbf5d7220c1c0d2d2c793a69d9bbaa1a1a9ec16611ad1b1d303d5d6" -} diff --git a/.sqlx/query-0d0bd23849e3e9492531fa8ce0eb22832d0c16d690cebbcb7e546cab3e942d64.json b/.sqlx/query-3ad4ff83b0317ee316f6e6d589d77a6f509d868de28d5b2b3724d66059223aaa.json similarity index 57% rename from .sqlx/query-0d0bd23849e3e9492531fa8ce0eb22832d0c16d690cebbcb7e546cab3e942d64.json rename to .sqlx/query-3ad4ff83b0317ee316f6e6d589d77a6f509d868de28d5b2b3724d66059223aaa.json index 36e97b5..db3812c 100644 --- a/.sqlx/query-0d0bd23849e3e9492531fa8ce0eb22832d0c16d690cebbcb7e546cab3e942d64.json +++ b/.sqlx/query-3ad4ff83b0317ee316f6e6d589d77a6f509d868de28d5b2b3724d66059223aaa.json @@ -1,12 +1,12 @@ { "db_name": "SQLite", - "query": "UPDATE calendars SET principal = ?, id = ?, displayname = ?, description = ?, \"order\" = ?, color = ?, timezone = ?, timezone_id = ?\n WHERE (principal, id) = (?, ?)", + "query": "UPDATE calendars SET principal = ?, id = ?, displayname = ?, description = ?, \"order\" = ?, color = ?, timezone = ?, timezone_id = ?, push_topic = ?\n WHERE (principal, id) = (?, ?)", "describe": { "columns": [], "parameters": { - "Right": 10 + "Right": 11 }, "nullable": [] }, - "hash": "0d0bd23849e3e9492531fa8ce0eb22832d0c16d690cebbcb7e546cab3e942d64" + "hash": "3ad4ff83b0317ee316f6e6d589d77a6f509d868de28d5b2b3724d66059223aaa" } diff --git a/.sqlx/query-51313b93f21cef5b82eb1b5a583940a6f74ba19fbf717f4d6f7351cdae4def0d.json b/.sqlx/query-508adcac37e0d6751924f65e9aed24c0185ce3b1bc39fd0eab7426f581aafe02.json similarity index 52% rename from .sqlx/query-51313b93f21cef5b82eb1b5a583940a6f74ba19fbf717f4d6f7351cdae4def0d.json rename to .sqlx/query-508adcac37e0d6751924f65e9aed24c0185ce3b1bc39fd0eab7426f581aafe02.json index 0b636a0..6202959 100644 --- a/.sqlx/query-51313b93f21cef5b82eb1b5a583940a6f74ba19fbf717f4d6f7351cdae4def0d.json +++ b/.sqlx/query-508adcac37e0d6751924f65e9aed24c0185ce3b1bc39fd0eab7426f581aafe02.json @@ -1,12 +1,12 @@ { "db_name": "SQLite", - "query": "INSERT INTO addressbooks (principal, id, displayname, description)\n VALUES (?, ?, ?, ?)", + "query": "INSERT INTO addressbooks (principal, id, displayname, description, push_topic)\n VALUES (?, ?, ?, ?, ?)", "describe": { "columns": [], "parameters": { - "Right": 4 + "Right": 5 }, "nullable": [] }, - "hash": "51313b93f21cef5b82eb1b5a583940a6f74ba19fbf717f4d6f7351cdae4def0d" + "hash": "508adcac37e0d6751924f65e9aed24c0185ce3b1bc39fd0eab7426f581aafe02" } diff --git a/.sqlx/query-24ece624823b418fa96a867f57d62ed755035e88b0d9363b71aac8aedff1cbb6.json b/.sqlx/query-6d32ecdc8dbd73ba917f2e5f89df445ac48f7e438f1d99519dad49a127399971.json similarity index 82% rename from .sqlx/query-24ece624823b418fa96a867f57d62ed755035e88b0d9363b71aac8aedff1cbb6.json rename to .sqlx/query-6d32ecdc8dbd73ba917f2e5f89df445ac48f7e438f1d99519dad49a127399971.json index ec17f6b..d065781 100644 --- a/.sqlx/query-24ece624823b418fa96a867f57d62ed755035e88b0d9363b71aac8aedff1cbb6.json +++ b/.sqlx/query-6d32ecdc8dbd73ba917f2e5f89df445ac48f7e438f1d99519dad49a127399971.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, displayname, \"order\", description, color, timezone, timezone_id, deleted_at, subscription_url\n FROM calendars\n WHERE principal = ? AND deleted_at IS NULL", + "query": "SELECT principal, id, synctoken, displayname, \"order\", description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic\n FROM calendars\n WHERE principal = ? AND deleted_at IS NULL", "describe": { "columns": [ { @@ -57,6 +57,11 @@ "name": "subscription_url", "ordinal": 10, "type_info": "Text" + }, + { + "name": "push_topic", + "ordinal": 11, + "type_info": "Text" } ], "parameters": { @@ -73,8 +78,9 @@ true, true, true, - true + true, + false ] }, - "hash": "24ece624823b418fa96a867f57d62ed755035e88b0d9363b71aac8aedff1cbb6" + "hash": "6d32ecdc8dbd73ba917f2e5f89df445ac48f7e438f1d99519dad49a127399971" } diff --git a/.sqlx/query-65c6f1c6c3e7d587f3f9a126260a0e12c5d372c754ddaf0d2a1d7b65e0119799.json b/.sqlx/query-9be5d6df7d30a9a85aece59be810bbbb203bab874860aa05eb311259e4baaf05.json similarity index 72% rename from .sqlx/query-65c6f1c6c3e7d587f3f9a126260a0e12c5d372c754ddaf0d2a1d7b65e0119799.json rename to .sqlx/query-9be5d6df7d30a9a85aece59be810bbbb203bab874860aa05eb311259e4baaf05.json index 1013ba5..4b12390 100644 --- a/.sqlx/query-65c6f1c6c3e7d587f3f9a126260a0e12c5d372c754ddaf0d2a1d7b65e0119799.json +++ b/.sqlx/query-9be5d6df7d30a9a85aece59be810bbbb203bab874860aa05eb311259e4baaf05.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, displayname, description, deleted_at\n FROM addressbooks\n WHERE principal = ? AND deleted_at IS NULL", + "query": "SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic\n FROM addressbooks\n WHERE principal = ? AND deleted_at IS NULL", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "name": "deleted_at", "ordinal": 5, "type_info": "Datetime" + }, + { + "name": "push_topic", + "ordinal": 6, + "type_info": "Text" } ], "parameters": { @@ -43,8 +48,9 @@ false, true, true, - true + true, + false ] }, - "hash": "65c6f1c6c3e7d587f3f9a126260a0e12c5d372c754ddaf0d2a1d7b65e0119799" + "hash": "9be5d6df7d30a9a85aece59be810bbbb203bab874860aa05eb311259e4baaf05" } diff --git a/.sqlx/query-9770a3a1c85aa92e7787ede67e86aa680e0831613cc9cb87cb19928fc538d35c.json b/.sqlx/query-ad596abc6b3826251bdf640ece558fde44fcbd4f7d27c283658de38330bef095.json similarity index 81% rename from .sqlx/query-9770a3a1c85aa92e7787ede67e86aa680e0831613cc9cb87cb19928fc538d35c.json rename to .sqlx/query-ad596abc6b3826251bdf640ece558fde44fcbd4f7d27c283658de38330bef095.json index 0f51cdf..a011339 100644 --- a/.sqlx/query-9770a3a1c85aa92e7787ede67e86aa680e0831613cc9cb87cb19928fc538d35c.json +++ b/.sqlx/query-ad596abc6b3826251bdf640ece558fde44fcbd4f7d27c283658de38330bef095.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, displayname, \"order\", description, color, timezone, timezone_id, deleted_at, subscription_url\n FROM calendars\n WHERE principal = ? AND deleted_at IS NOT NULL", + "query": "SELECT principal, id, synctoken, displayname, \"order\", description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic\n FROM calendars\n WHERE principal = ? AND deleted_at IS NOT NULL", "describe": { "columns": [ { @@ -57,6 +57,11 @@ "name": "subscription_url", "ordinal": 10, "type_info": "Text" + }, + { + "name": "push_topic", + "ordinal": 11, + "type_info": "Text" } ], "parameters": { @@ -73,8 +78,9 @@ true, true, true, - true + true, + false ] }, - "hash": "9770a3a1c85aa92e7787ede67e86aa680e0831613cc9cb87cb19928fc538d35c" + "hash": "ad596abc6b3826251bdf640ece558fde44fcbd4f7d27c283658de38330bef095" } diff --git a/.sqlx/query-c0d889d0738797185b10ec3e5134b804579ad4300fd8227b0d6f307281f25111.json b/.sqlx/query-c0d889d0738797185b10ec3e5134b804579ad4300fd8227b0d6f307281f25111.json new file mode 100644 index 0000000..7513c73 --- /dev/null +++ b/.sqlx/query-c0d889d0738797185b10ec3e5134b804579ad4300fd8227b0d6f307281f25111.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO calendars (principal, id, displayname, description, \"order\", color, timezone, timezone_id, push_topic)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 9 + }, + "nullable": [] + }, + "hash": "c0d889d0738797185b10ec3e5134b804579ad4300fd8227b0d6f307281f25111" +} diff --git a/.sqlx/query-d1dd991de4ba20fd7940ae0dbe5d6c1298ed928adbf51e2fcacd060b518786c7.json b/.sqlx/query-c736a652873a4795bb7a9bd96db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b.json similarity index 73% rename from .sqlx/query-d1dd991de4ba20fd7940ae0dbe5d6c1298ed928adbf51e2fcacd060b518786c7.json rename to .sqlx/query-c736a652873a4795bb7a9bd96db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b.json index e9c9a00..b5385f8 100644 --- a/.sqlx/query-d1dd991de4ba20fd7940ae0dbe5d6c1298ed928adbf51e2fcacd060b518786c7.json +++ b/.sqlx/query-c736a652873a4795bb7a9bd96db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, displayname, description, deleted_at\n FROM addressbooks\n WHERE (principal, id) = (?, ?)", + "query": "SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic\n FROM addressbooks\n WHERE (principal, id) = (?, ?)", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "name": "deleted_at", "ordinal": 5, "type_info": "Datetime" + }, + { + "name": "push_topic", + "ordinal": 6, + "type_info": "Text" } ], "parameters": { @@ -43,8 +48,9 @@ false, true, true, - true + true, + false ] }, - "hash": "d1dd991de4ba20fd7940ae0dbe5d6c1298ed928adbf51e2fcacd060b518786c7" + "hash": "c736a652873a4795bb7a9bd96db5b41ec7e5bfba5e00aea8f7a0fa406a8d518b" } diff --git a/.sqlx/query-d8a41068baadd14fd412d2cbdf054f2fbb9bedea0ec2a0f06ed25d30a02338d3.json b/.sqlx/query-d8a41068baadd14fd412d2cbdf054f2fbb9bedea0ec2a0f06ed25d30a02338d3.json deleted file mode 100644 index 6187ff9..0000000 --- a/.sqlx/query-d8a41068baadd14fd412d2cbdf054f2fbb9bedea0ec2a0f06ed25d30a02338d3.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "UPDATE addressbooks SET principal = ?, id = ?, displayname = ?, description = ?\n WHERE (principal, id) = (?, ?)", - "describe": { - "columns": [], - "parameters": { - "Right": 6 - }, - "nullable": [] - }, - "hash": "d8a41068baadd14fd412d2cbdf054f2fbb9bedea0ec2a0f06ed25d30a02338d3" -} diff --git a/.sqlx/query-34e911d0f7f176cbd66ed6eb1cad7b2eb5b87acccfe9a69b1dcce05c1c303705.json b/.sqlx/query-e5ded4814aae1fc033bb90d27c745f76d3799958d929e8e8d16aa3ceff98e72d.json similarity index 72% rename from .sqlx/query-34e911d0f7f176cbd66ed6eb1cad7b2eb5b87acccfe9a69b1dcce05c1c303705.json rename to .sqlx/query-e5ded4814aae1fc033bb90d27c745f76d3799958d929e8e8d16aa3ceff98e72d.json index 894bc38..c216fa6 100644 --- a/.sqlx/query-34e911d0f7f176cbd66ed6eb1cad7b2eb5b87acccfe9a69b1dcce05c1c303705.json +++ b/.sqlx/query-e5ded4814aae1fc033bb90d27c745f76d3799958d929e8e8d16aa3ceff98e72d.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT principal, id, synctoken, displayname, description, deleted_at\n FROM addressbooks\n WHERE principal = ? AND deleted_at IS NOT NULL", + "query": "SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic\n FROM addressbooks\n WHERE principal = ? AND deleted_at IS NOT NULL", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "name": "deleted_at", "ordinal": 5, "type_info": "Datetime" + }, + { + "name": "push_topic", + "ordinal": 6, + "type_info": "Text" } ], "parameters": { @@ -43,8 +48,9 @@ false, true, true, - true + true, + false ] }, - "hash": "34e911d0f7f176cbd66ed6eb1cad7b2eb5b87acccfe9a69b1dcce05c1c303705" + "hash": "e5ded4814aae1fc033bb90d27c745f76d3799958d929e8e8d16aa3ceff98e72d" } diff --git a/Cargo.lock b/Cargo.lock index 8e98954..dc556aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2631,6 +2631,7 @@ dependencies = [ "tracing", "tracing-actix-web", "url", + "uuid", ] [[package]] @@ -2656,6 +2657,7 @@ dependencies = [ "tracing", "tracing-actix-web", "url", + "uuid", ] [[package]] @@ -3721,6 +3723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" dependencies = [ "getrandom", + "rand", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5d307fa..b7f59b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ publish = false debug = 0 [workspace.dependencies] +uuid = { version = "1.11", features = ["v4", "fast-rng"] } async-trait = "0.1" actix-web = "4.9" tracing = { version = "0.1", features = ["async-await"] } @@ -98,7 +99,6 @@ quote = "1.0" proc-macro2 = "1.0" heck = "0.5" darling = "0.20" - [dependencies] rustical_store = { workspace = true } rustical_store_sqlite = { workspace = true } diff --git a/crates/caldav/Cargo.toml b/crates/caldav/Cargo.toml index 5a0c01a..6460d2c 100644 --- a/crates/caldav/Cargo.toml +++ b/crates/caldav/Cargo.toml @@ -27,3 +27,4 @@ rustical_store = { workspace = true } chrono = { workspace = true } sha2 = { workspace = true } rustical_xml.workspace = true +uuid.workspace = true diff --git a/crates/caldav/src/calendar/methods/mkcalendar.rs b/crates/caldav/src/calendar/methods/mkcalendar.rs index d5eaeed..b6a9110 100644 --- a/crates/caldav/src/calendar/methods/mkcalendar.rs +++ b/crates/caldav/src/calendar/methods/mkcalendar.rs @@ -68,6 +68,7 @@ pub async fn route_mkcalendar( deleted_at: None, synctoken: 0, subscription_url: None, + push_topic: uuid::Uuid::new_v4().to_string(), }; match store.insert_calendar(calendar).await { diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 66fcc67..06af369 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -17,7 +17,6 @@ use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; use rustical_store::{Calendar, CalendarStore}; use rustical_xml::{XmlDeserialize, XmlSerialize}; -use sha2::{Digest, Sha256}; use std::str::FromStr; use std::sync::Arc; use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; @@ -36,9 +35,6 @@ pub enum CalendarProp { Getcontenttype(&'static str), // WebDav Push - // NOTE: Here we implement an older version of the spec since the new property name is not reflected - // in DAVx5 yet - // https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3 #[xml(skip_deserializing)] #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] Transports(Transports), @@ -141,16 +137,7 @@ impl Resource for CalendarResource { CalendarProp::Getcontenttype("text/calendar;charset=utf-8") } CalendarPropName::Transports => CalendarProp::Transports(Default::default()), - CalendarPropName::Topic => { - // TODO: Add salt since this could be public - // let url = - // CalendarResource::get_url(rmap, [&self.cal.principal, &self.cal.id]).unwrap(); - let url = "TODO!".to_owned(); - let mut hasher = Sha256::new(); - hasher.update(url); - let topic = format!("{:x}", hasher.finalize()); - CalendarProp::Topic(topic) - } + CalendarPropName::Topic => CalendarProp::Topic(self.cal.push_topic.to_owned()), CalendarPropName::MaxResourceSize => CalendarProp::MaxResourceSize(10000000), CalendarPropName::SupportedReportSet => { CalendarProp::SupportedReportSet(SupportedReportSet::default()) diff --git a/crates/carddav/Cargo.toml b/crates/carddav/Cargo.toml index 3fd4393..e4bf941 100644 --- a/crates/carddav/Cargo.toml +++ b/crates/carddav/Cargo.toml @@ -26,3 +26,4 @@ rustical_dav = { workspace = true } rustical_store = { workspace = true } chrono = { workspace = true } rustical_xml.workspace = true +uuid.workspace = true diff --git a/crates/carddav/src/addressbook/methods/mkcol.rs b/crates/carddav/src/addressbook/methods/mkcol.rs index 87cc5da..46584da 100644 --- a/crates/carddav/src/addressbook/methods/mkcol.rs +++ b/crates/carddav/src/addressbook/methods/mkcol.rs @@ -54,6 +54,7 @@ pub async fn route_mkcol( description: request.description, deleted_at: None, synctoken: 0, + push_topic: uuid::Uuid::new_v4().to_string(), }; match store.get_addressbook(&principal, &addressbook_id).await { diff --git a/crates/store/src/addressbook/addressbook.rs b/crates/store/src/addressbook/addressbook.rs index 765055c..98c332b 100644 --- a/crates/store/src/addressbook/addressbook.rs +++ b/crates/store/src/addressbook/addressbook.rs @@ -10,6 +10,7 @@ pub struct Addressbook { pub description: Option, pub deleted_at: Option, pub synctoken: i64, + pub push_topic: String, } impl Addressbook { diff --git a/crates/store/src/calendar/calendar.rs b/crates/store/src/calendar/calendar.rs index 4a9d2cf..58bdd0b 100644 --- a/crates/store/src/calendar/calendar.rs +++ b/crates/store/src/calendar/calendar.rs @@ -15,6 +15,7 @@ pub struct Calendar { pub deleted_at: Option, pub synctoken: i64, pub subscription_url: Option, + pub push_topic: String, } impl Calendar { diff --git a/crates/store/src/contact_birthday_store.rs b/crates/store/src/contact_birthday_store.rs index eefb26a..c3e93c0 100644 --- a/crates/store/src/contact_birthday_store.rs +++ b/crates/store/src/contact_birthday_store.rs @@ -5,6 +5,7 @@ use crate::{ }; use async_trait::async_trait; use derive_more::derive::Constructor; +use sha2::{Digest, Sha256}; #[derive(Constructor, Clone)] pub struct ContactBirthdayStore(Arc); @@ -24,6 +25,12 @@ fn birthday_calendar(addressbook: Addressbook) -> Calendar { deleted_at: addressbook.deleted_at, synctoken: addressbook.synctoken, subscription_url: None, + push_topic: { + let mut hasher = Sha256::new(); + hasher.update("birthdays"); + hasher.update(addressbook.push_topic); + format!("{:x}", hasher.finalize()) + }, } } diff --git a/crates/store_sqlite/migrations/1_calendar.sql b/crates/store_sqlite/migrations/1_calendar.sql index 4dd10eb..fa27e9b 100644 --- a/crates/store_sqlite/migrations/1_calendar.sql +++ b/crates/store_sqlite/migrations/1_calendar.sql @@ -10,6 +10,7 @@ CREATE TABLE calendars ( timezone_id TEXT, deleted_at DATETIME, subscription_url TEXT, + push_topic TEXT UNIQUE NOT NULL, PRIMARY KEY (principal, id) ); diff --git a/crates/store_sqlite/migrations/2_addressbook.sql b/crates/store_sqlite/migrations/2_addressbook.sql index dac0d97..9ed621a 100644 --- a/crates/store_sqlite/migrations/2_addressbook.sql +++ b/crates/store_sqlite/migrations/2_addressbook.sql @@ -5,6 +5,7 @@ CREATE TABLE addressbooks ( displayname TEXT, description TEXT, deleted_at DATETIME, + push_topic TEXT UNIQUE NOT NULL, PRIMARY KEY (principal, id) ); diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index 13d58ad..3079f40 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -63,7 +63,7 @@ impl AddressbookStore for SqliteStore { ) -> Result { let addressbook = sqlx::query_as!( Addressbook, - r#"SELECT principal, id, synctoken, displayname, description, deleted_at + r#"SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic FROM addressbooks WHERE (principal, id) = (?, ?)"#, principal, @@ -82,7 +82,7 @@ impl AddressbookStore for SqliteStore { ) -> Result, rustical_store::Error> { let addressbooks = sqlx::query_as!( Addressbook, - r#"SELECT principal, id, synctoken, displayname, description, deleted_at + r#"SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic FROM addressbooks WHERE principal = ? AND deleted_at IS NULL"#, principal @@ -100,7 +100,7 @@ impl AddressbookStore for SqliteStore { ) -> Result, rustical_store::Error> { let addressbooks = sqlx::query_as!( Addressbook, - r#"SELECT principal, id, synctoken, displayname, description, deleted_at + r#"SELECT principal, id, synctoken, displayname, description, deleted_at, push_topic FROM addressbooks WHERE principal = ? AND deleted_at IS NOT NULL"#, principal @@ -119,12 +119,13 @@ impl AddressbookStore for SqliteStore { addressbook: Addressbook, ) -> Result<(), rustical_store::Error> { let result = sqlx::query!( - r#"UPDATE addressbooks SET principal = ?, id = ?, displayname = ?, description = ? + r#"UPDATE addressbooks SET principal = ?, id = ?, displayname = ?, description = ?, push_topic = ? WHERE (principal, id) = (?, ?)"#, addressbook.principal, addressbook.id, addressbook.displayname, addressbook.description, + addressbook.push_topic, principal, id ) @@ -143,12 +144,13 @@ impl AddressbookStore for SqliteStore { addressbook: Addressbook, ) -> Result<(), rustical_store::Error> { sqlx::query!( - r#"INSERT INTO addressbooks (principal, id, displayname, description) - VALUES (?, ?, ?, ?)"#, + r#"INSERT INTO addressbooks (principal, id, displayname, description, push_topic) + VALUES (?, ?, ?, ?, ?)"#, addressbook.principal, addressbook.id, addressbook.displayname, addressbook.description, + addressbook.push_topic, ) .execute(&self.db) .await diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 067309d..c74c97e 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -62,7 +62,7 @@ impl CalendarStore for SqliteStore { async fn get_calendar(&self, principal: &str, id: &str) -> Result { let cal = sqlx::query_as!( Calendar, - r#"SELECT principal, id, synctoken, "order", displayname, description, color, timezone, timezone_id, deleted_at, subscription_url + r#"SELECT principal, id, synctoken, "order", displayname, description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic FROM calendars WHERE (principal, id) = (?, ?)"#, principal, @@ -77,7 +77,7 @@ impl CalendarStore for SqliteStore { async fn get_calendars(&self, principal: &str) -> Result, Error> { let cals = sqlx::query_as!( Calendar, - r#"SELECT principal, id, synctoken, displayname, "order", description, color, timezone, timezone_id, deleted_at, subscription_url + r#"SELECT principal, id, synctoken, displayname, "order", description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic FROM calendars WHERE principal = ? AND deleted_at IS NULL"#, principal @@ -91,7 +91,7 @@ impl CalendarStore for SqliteStore { async fn get_deleted_calendars(&self, principal: &str) -> Result, Error> { let cals = sqlx::query_as!( Calendar, - r#"SELECT principal, id, synctoken, displayname, "order", description, color, timezone, timezone_id, deleted_at, subscription_url + r#"SELECT principal, id, synctoken, displayname, "order", description, color, timezone, timezone_id, deleted_at, subscription_url, push_topic FROM calendars WHERE principal = ? AND deleted_at IS NOT NULL"#, principal @@ -104,8 +104,8 @@ impl CalendarStore for SqliteStore { #[instrument] async fn insert_calendar(&self, calendar: Calendar) -> Result<(), Error> { sqlx::query!( - r#"INSERT INTO calendars (principal, id, displayname, description, "order", color, timezone, timezone_id) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)"#, + r#"INSERT INTO calendars (principal, id, displayname, description, "order", color, timezone, timezone_id, push_topic) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"#, calendar.principal, calendar.id, calendar.displayname, @@ -113,7 +113,8 @@ impl CalendarStore for SqliteStore { calendar.order, calendar.color, calendar.timezone, - calendar.timezone_id + calendar.timezone_id, + calendar.push_topic, ) .execute(&self.db) .await.map_err(crate::Error::from)?; @@ -128,7 +129,7 @@ impl CalendarStore for SqliteStore { calendar: Calendar, ) -> Result<(), Error> { let result = sqlx::query!( - r#"UPDATE calendars SET principal = ?, id = ?, displayname = ?, description = ?, "order" = ?, color = ?, timezone = ?, timezone_id = ? + r#"UPDATE calendars SET principal = ?, id = ?, displayname = ?, description = ?, "order" = ?, color = ?, timezone = ?, timezone_id = ?, push_topic = ? WHERE (principal, id) = (?, ?)"#, calendar.principal, calendar.id, @@ -138,6 +139,7 @@ impl CalendarStore for SqliteStore { calendar.color, calendar.timezone, calendar.timezone_id, + calendar.push_topic, principal, id ).execute(&self.db).await.map_err(crate::Error::from)?;