on master help sign in
Fix server gossip race, DoS, validation ordering, and status reporting

- Fix VerifyAuth gossip race: filter expired user from offline gossip to prevent overwriting online status - Fix DoS in AckMessages/FederationAck: move count check before expensive validation - Fix validation ordering: check tooLong before isValidHex in 6 locations - Fix SendMessage: fall back to "queued" instead of "federated" when federation disabled

commit964dd2277169d01ba06d7ea6bffed8cabda1d353 authoriko <mail@iko.soy> dateFri 27 Mar 2026, 17:42 (7 months ago) parentfa9d38a
54 files changed+49−66
client/ApiClient.fs+6−1 client/App.fs+14−7 client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4 client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2 client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt−22 client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1 client/obj/Debug/net10.0-ios/iossimulator-arm64/linked/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/linked/Skrepka.pdb client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stamp client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xml−6 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/linked/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/linked/Skrepka.pdb client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll server.knot+17−18
client/ApiClient.fs+6−1
@@ -107,7 +107,12 @@ module ApiClient =
107107 if e.ValueKind = JsonValueKind.Object then
108108 let id = e.GetProperty("id").GetString()
109109 let evtType = e.GetProperty("eventType").GetString()
110− let payload = e.GetProperty("payload").GetString()
110+ let payloadEl = e.GetProperty("payload")
111+ let payload =
112+ if payloadEl.ValueKind = JsonValueKind.String then
113+ payloadEl.GetString()
114+ else
115+ payloadEl.GetRawText()
111116 yield (id, evtType, payload) ]
112117
113118 return (events, cursor)
client/App.fs+14−7
@@ -47,7 +47,8 @@ module App =
4747 NewPubkey: string
4848 NewNickname: string
4949 Error: string option
50− PollCursor: int64 }
50+ PollCursor: int64
51+ LastSendStatus: string }
5152
5253 // ── Msg ──
5354
@@ -114,7 +115,8 @@ module App =
114115 NewPubkey = ""
115116 NewNickname = ""
116117 Error = None
117− PollCursor = 0L },
118+ PollCursor = 0L
119+ LastSendStatus = "" },
118120 []
119121
120122 // ── Update ──
@@ -170,7 +172,7 @@ module App =
170172 [ CmdSend(model.ServerUrl, token, pk, priv, model.PubKeyHex, pk, text) ]
171173 | _ -> model, []
172174
173− | Sent _ -> model, []
175+ | Sent(_, status) -> { model with LastSendStatus = status }, []
174176
175177 | PollResult(incoming, status, newCursor) ->
176178 let model' =
@@ -290,8 +292,8 @@ module App =
290292
291293 let blob = Crypto.encrypt privKey pubKey recipPub payload
292294 let blobHex = Crypto.toHex blob
293− let! (_, msgId) = ApiClient.sendMessage url token toHex blobHex ts
294− return Sent(toHex, msgId)
295+ let! (status, msgId) = ApiClient.sendMessage url token toHex blobHex ts
296+ return Sent(toHex, $"{status}:{msgId}")
295297 with ex ->
296298 return DismissError // TODO: show send errors properly
297299 })
@@ -309,7 +311,12 @@ module App =
309311 try
310312 let doc = JsonDocument.Parse(payload)
311313 let blobHex = doc.RootElement.GetProperty("encryptedBlob").GetString()
312− let ts = doc.RootElement.GetProperty("timestamp").GetInt64()
314+ let tsEl = doc.RootElement.GetProperty("timestamp")
315+ let ts =
316+ if tsEl.ValueKind = JsonValueKind.String then
317+ Int64.Parse(tsEl.GetString())
318+ else
319+ tsEl.GetInt64()
313320 let blob = Crypto.fromHex blobHex
314321
315322 match Crypto.decrypt privKey blob with
@@ -490,7 +497,7 @@ module App =
490497 .textColor(Colors.Red)
491498 .font(size = 11.)
492499
493− Label($"[{msgs.Length} message(s), compose: \"{model.ComposeText}\"]")
500+ Label($"[{msgs.Length} message(s), compose: \"{model.ComposeText}\", send: \"{model.LastSendStatus}\"]")
494501 .textColor(Colors.Gray)
495502 .font(size = 10.)
496503
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4
@@ -162,11 +162,11 @@
162162 </data>
163163 <key>Skrepka.dll</key>
164164 <data>
165− ihxkdJmILCX2rvNfx8IAKfrjiRw=
165+ 27gfq5dZ4/eTxH0f4bw8bUDiS2M=
166166 </data>
167167 <key>Skrepka.pdb</key>
168168 <data>
169− 5Ef95J0Y0SPaPbiv94B4OI5dvt4=
169+ D3LomwjioLVqeXPIjplXlbfcC4g=
170170 </data>
171171 <key>Sodium.Core.dll</key>
172172 <data>
@@ -1382,14 +1382,14 @@
13821382 <dict>
13831383 <key>hash2</key>
13841384 <data>
1385− jA699ETKlhsSyP0dr9yKgsVa246KniFBNn6h+H093lI=
1385+ 8/yNqmUXv1KVEP6mJx7cV8riXCRkhMvDIW09gUJw6wk=
13861386 </data>
13871387 </dict>
13881388 <key>Skrepka.pdb</key>
13891389 <dict>
13901390 <key>hash2</key>
13911391 <data>
1392− 9xCu8W4xbM0EJu+r0fyBhBs95Lz7i0LEqYeCvuPHiYQ=
1392+ uF/IJAfKHG3onHFR8ScB160+btmHZaJqGiJNzR07nu0=
13931393 </data>
13941394 </dict>
13951395 <key>Sodium.Core.dll</key>
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2
@@ -240,14 +240,14 @@
240240 <dict>
241241 <key>hash2</key>
242242 <data>
243− SkrTLt6NpdxkCOrg3x+0va15w21CQqSaHXDAj+klfQY=
243+ vUKSK+cGYTR7qkuQmbqO8GnXw8MSCSGfEnat9WPM61k=
244244 </data>
245245 </dict>
246246 <key>MonoBundle/Skrepka.pdb</key>
247247 <dict>
248248 <key>hash2</key>
249249 <data>
250− 1pt18PVRQANYqIOx8PEoowFdG5ubKia23BbX/3qPn2Q=
250+ G384EqZj+qubQ4QYr5jq66KSfqzCb5lMDtIbdeDt3Es=
251251 </data>
252252 </dict>
253253 <key>MonoBundle/Sodium.Core.dll</key>
client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
1010[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
1111[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
1212[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+1025ec42bdc63a36e82c2b05547b3ddfc72a0761")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+fa9d38a3fad244670e1576c664bf6ba789d0168e")>]
1414[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
1515[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
1616[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−608be3485c5b02f0859bc57c944a7d90f027c871f4620f1b2625c376aa40ab39
1+5f2895c26967c1b79537d5958be98264c62028600e0beb408e514bf6fedba7a8
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt−22
@@ -333,25 +333,3 @@
333333/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb
334334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
335335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
336−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stamp
337−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stamp
338−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stamp
339−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stamp
340−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stamp
341−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stamp
342−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stamp
343−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stamp
344−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stamp
345−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stamp
346−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stamp
347−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stamp
348−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stamp
349−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stamp
350−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stamp
351−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stamp
352−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stamp
353−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stamp
354−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stamp
355−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stamp
356−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stamp
357−/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xml
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/1025ec42bdc63a36e82c2b05547b3ddfc72a0761/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/fa9d38a3fad244670e1576c664bf6ba789d0168e/*"}}
client/obj/Debug/net10.0-ios/iossimulator-arm64/linked/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/linked/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stampdeleted

No changes to the content.

client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xmldeleted−6
@@ -1,6 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8" ?>
2−<paths>
3− <external-path name="external_files" path="." />
4− <cache-path name="internal_cache" path="." />
5− <external-cache-path name="external_cache" path="." />
6−</paths>
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
1010[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
1111[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
1212[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+1025ec42bdc63a36e82c2b05547b3ddfc72a0761")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+fa9d38a3fad244670e1576c664bf6ba789d0168e")>]
1414[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
1515[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
1616[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−6ce084ea2001e68a95078f1ad7ce56a873907d46e9df803c23a3c8e674e8ede8
1+284a452a2358d44d43d128fc8940476c0b2aae618df88f49906b03be966d2822
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/1025ec42bdc63a36e82c2b05547b3ddfc72a0761/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/fa9d38a3fad244670e1576c664bf6ba789d0168e/*"}}
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/linked/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/linked/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll

Binary file not shown.

server.knot+17−18
@@ -114,10 +114,6 @@ verifyFederationAuth = \authorization ->
114114
115115clampTtl = \ttl -> if ttl < 1 then 1 else if ttl > maxPresenceTtl then maxPresenceTtl else ttl
116116
117−forwardToAll = \servers action -> do
118− sendToEach servers (\server -> action server)
119− yield (count servers > 0)
120−
121117sendToEach = \servers action ->
122118 if count servers == 0
123119 then yield {}
@@ -270,7 +266,10 @@ serve = \req -> case req of
270266 authorization: "Bearer " ++ federationSecret,
271267 events: [{eventType: "online", pubkey: pubkey, server: serverHost, timestamp: t, ttl: 3600}], hopsRemaining: 2, fromServer: serverHost}))
272268 else yield {}
273− broadcastOfflineGossip t result.offlinePeers result.expiredLocal
269+ broadcastOfflineGossip t result.offlinePeers (do
270+ p <- result.expiredLocal
271+ where not (p.pubkey == pubkey)
272+ yield p)
274273 if result.sigValid
275274 then respond {token: token, expiresAt: expiry}
276275 else respond {token: "", expiresAt: 0}
@@ -309,7 +308,7 @@ serve = \req -> case req of
309308 t <- now
310309 msgId <- genToken
311310 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t else timestamp
312− let validInput = not (to == "") && not (encryptedBlob == "") && isValidHex to && isValidHex encryptedBlob && not (tooLong to maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen)
311+ let validInput = not (to == "") && not (encryptedBlob == "") && not (tooLong to maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen) && isValidHex to && isValidHex encryptedBlob
313312 result <- atomic do
314313 pr <- pruneExpired t
315314 sessions <- *sessions
@@ -357,13 +356,13 @@ serve = \req -> case req of
357356 yield {status: status, remoteServers: remoteServers, fromKey: fromKey, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
358357 finalStatus <- if result.status == "federated" && not (federationSecret == "")
359358 then do
360− anyOk <- forwardToAll result.remoteServers (\server ->
359+ sendToEach result.remoteServers (\server ->
361360 fetch (federationScheme ++ server) (ForwardMessage {
362361 toKey: to, fromKey: result.fromKey, encryptedBlob: encryptedBlob,
363362 timestamp: clampedTs, originServer: serverHost, messageId: msgId,
364363 authorization: "Bearer " ++ federationSecret}))
365− yield (if anyOk then "federated" else "queued")
366− else yield result.status
364+ yield "federated"
365+ else yield (if result.status == "federated" then "queued" else result.status)
367366 broadcastOfflineGossip t result.peerServers result.expiredLocal
368367 respond {status: finalStatus, messageId: (if result.status == "unauthorized" then "" else if result.status == "invalid" then "" else msgId)}
369368
@@ -371,9 +370,9 @@ serve = \req -> case req of
371370 t <- now
372371 let dedupedIds = fold (\acc mid ->
373372 if mid == "" then acc
374− else if not (isValidHex mid) then acc
375− else if tooLong mid maxPubkeyLen then acc
376373 else if count acc >= maxMessageIds then acc
374+ else if tooLong mid maxPubkeyLen then acc
375+ else if not (isValidHex mid) then acc
377376 else if count (do a <- acc; where a == mid; yield a) > 0 then acc
378377 else union acc [mid]) [] messageIds
379378 result <- atomic do
@@ -439,7 +438,7 @@ serve = \req -> case req of
439438 where p.server == serverHost
440439 yield p) of
441440 Just {value: p} -> p.server
442− Nothing {} -> fold (\_ p -> p.server) "" valid
441+ Nothing {} -> (fold (\acc p -> if p.expiresAt > acc.best then {server: p.server, best: p.expiresAt} else acc) {server: "", best: 0} valid).server
443442 yield {foundServer: foundServer, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
444443 broadcastOfflineGossip t result.peerServers result.expiredLocal
445444 respond {online: not (result.foundServer == ""), server: result.foundServer, authorized: result.authorized}
@@ -455,9 +454,9 @@ serve = \req -> case req of
455454 where e.eventType == "online"
456455 where not (e.server == "")
457456 where not (e.pubkey == "")
458− where isValidHex e.pubkey
459457 where not (tooLong e.pubkey maxPubkeyLen)
460458 where not (tooLong e.server maxPubkeyLen)
459+ where isValidHex e.pubkey
461460 where not (e.server == serverHost)
462461 where e.timestamp <= t + clockSkewTolerance
463462 where e.timestamp + (clampTtl e.ttl) * 1000 > t
@@ -468,9 +467,9 @@ serve = \req -> case req of
468467 where e.eventType == "offline"
469468 where not (e.server == "")
470469 where not (e.pubkey == "")
471− where isValidHex e.pubkey
472470 where not (tooLong e.pubkey maxPubkeyLen)
473471 where not (tooLong e.server maxPubkeyLen)
472+ where isValidHex e.pubkey
474473 where not (e.server == serverHost)
475474 where e.timestamp <= t + clockSkewTolerance
476475 where t - e.timestamp < (clampTtl e.ttl) * 1000
@@ -570,9 +569,9 @@ serve = \req -> case req of
570569 where validRequest
571570 where not (e.server == "")
572571 where not (e.pubkey == "")
573− where isValidHex e.pubkey
574572 where not (tooLong e.pubkey maxPubkeyLen)
575573 where not (tooLong e.server maxPubkeyLen)
574+ where isValidHex e.pubkey
576575 where not (e.server == serverHost)
577576 where e.timestamp <= t + clockSkewTolerance
578577 where e.timestamp + (clampTtl e.ttl) * 1000 > t
@@ -614,7 +613,7 @@ serve = \req -> case req of
614613 t <- now
615614 let authorized = verifyFederationAuth authorization
616615 let validOrigin = not (originServer == "") && not (originServer == serverHost) && not (tooLong originServer maxPubkeyLen)
617− let validFields = not (toKey == "") && not (fromKey == "") && not (encryptedBlob == "") && not (messageId == "") && isValidHex toKey && isValidHex fromKey && isValidHex encryptedBlob && isValidHex messageId && not (tooLong toKey maxPubkeyLen) && not (tooLong fromKey maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen) && not (tooLong messageId maxPubkeyLen)
616+ let validFields = not (toKey == "") && not (fromKey == "") && not (encryptedBlob == "") && not (messageId == "") && not (tooLong toKey maxPubkeyLen) && not (tooLong fromKey maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen) && not (tooLong messageId maxPubkeyLen) && isValidHex toKey && isValidHex fromKey && isValidHex encryptedBlob && isValidHex messageId
618617 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t else timestamp
619618 pruneResult <- atomic do
620619 pr <- pruneExpired t
@@ -643,9 +642,9 @@ serve = \req -> case req of
643642 let authorized = verifyFederationAuth authorization
644643 let dedupedIds = fold (\acc mid ->
645644 if mid == "" then acc
646− else if not (isValidHex mid) then acc
647− else if tooLong mid maxPubkeyLen then acc
648645 else if count acc >= maxMessageIds then acc
646+ else if tooLong mid maxPubkeyLen then acc
647+ else if not (isValidHex mid) then acc
649648 else if count (do a <- acc; where a == mid; yield a) > 0 then acc
650649 else union acc [mid]) [] messageIds
651650 let validAck = authorized && originServer == serverHost && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen)