ENH - add DarkChat media attachments

This commit is contained in:
Leon.Schmidt
2026-08-06 22:50:38 +02:00
parent db29a3dd07
commit 509fdc7dbc
19 changed files with 499 additions and 101 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sky Phone</title>
<script type="module" crossorigin src="./assets/sky-index-nwsHiC9b.js"></script>
<link rel="stylesheet" crossorigin href="./assets/sky-index-BqvyRdgo.css">
<script type="module" crossorigin src="./assets/sky-index-BP8rWcLp.js"></script>
<link rel="stylesheet" crossorigin href="./assets/sky-index-DyRptftA.css">
</head>
<body>
<div id="app"></div>
+11
View File
@@ -490,6 +490,9 @@ Bridge.Callbacks.Register("sky_phone:darkchat:send", function(source, data)
if not SkyPhone.AllowOperation(source, "darkchat_send", Config.DarkChat.SendsPerMinute, 60) then
return { success = false, error = "rate_limited" }
end
if type(data) ~= "table" then
return { success = false, error = "invalid_request" }
end
local profile, _, error_response = require_profile(source)
if not profile then
return error_response
@@ -527,6 +530,14 @@ Bridge.Callbacks.Register("sky_phone:darkchat:send", function(source, data)
media_mime = voice.mime
media_duration = voice.duration
media_waveform = voice.waveform
elseif message_type == "image" or message_type == "video" then
local media_type = message_type == "image" and "photo" or "video"
local media_url, media_error = SkyPhoneMedia.ResolveOwnedMedia(source, data.mediaAssetId, media_type)
if not media_url then
return { success = false, error = media_error }
end
media_payload = media_url
media_mime = message_type == "image" and "image/jpeg" or "video/mp4"
else
return { success = false, error = "invalid_message" }
end
+5 -1
View File
@@ -746,7 +746,7 @@ local schema = {
{ name = "id", type = "CHAR(36) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
{ name = "conversation_id", type = "CHAR(36) NOT NULL", characterSet = "ascii", collation = "ascii_bin" },
{ name = "sender_profile_id", type = "BIGINT UNSIGNED NULL" },
{ name = "message_type", type = "ENUM('text', 'emoji', 'gif', 'voice', 'system') NOT NULL DEFAULT 'text'" },
{ name = "message_type", type = "ENUM('text', 'emoji', 'gif', 'voice', 'image', 'video', 'system') NOT NULL DEFAULT 'text'" },
{ name = "body", type = "TEXT NOT NULL" },
{ name = "media_payload", type = "LONGTEXT NULL" },
{ name = "media_mime", type = "VARCHAR(80) NULL", characterSet = "ascii", collation = "ascii_bin" },
@@ -819,6 +819,10 @@ Bridge.Database.Query([[
ALTER TABLE `sky_phone_sms_messages`
MODIFY COLUMN `message_type` ENUM('text', 'voice', 'image', 'gif', 'video') NOT NULL DEFAULT 'text'
]], {})
Bridge.Database.Query([[
ALTER TABLE `sky_phone_darkchat_messages`
MODIFY COLUMN `message_type` ENUM('text', 'emoji', 'gif', 'voice', 'image', 'video', 'system') NOT NULL DEFAULT 'text'
]], {})
Bridge.Database.EnsureIndex("sky_phone_devices", "uniq_sky_phone_devices_sim", "(`sim_id`)", { unique = true })
Bridge.Database.Query("UPDATE `sky_phone_contacts` SET `contact_id` = `id` WHERE `contact_id` IS NULL", {})
Bridge.Database.EnsureIndex("sky_phone_contacts", "uniq_sky_phone_contacts_account_contact", "(`account_id`, `contact_id`)", { unique = true })
+41 -2
View File
@@ -34,7 +34,7 @@ local function http_request(url, method, body, headers, timeout_ms)
settled = true
request:resolve({ status = 0, body = "request_timeout" })
end)
return Await(request)
return Citizen.Await(request)
end
local function decode_response(response)
@@ -136,6 +136,45 @@ local function owners_match(left, right)
return left.imei == right.imei and left.account_id == right.account_id
end
function SkyPhoneMedia.ResolveOwnedMedia(source, media_id, media_type)
local id = tonumber(media_id)
if not id or id < 1 or id ~= math.floor(id)
or (media_type ~= "photo" and media_type ~= "video")
then
return nil, "invalid_attachment"
end
local owner, error_response = session_owner(source)
if not owner then
return nil, error_response.error
end
local condition, owner_params = owner_condition(owner)
local params = { id }
for _, value in ipairs(owner_params) do
params[#params + 1] = value
end
local rows = Bridge.Database.Query(([[
SELECT `url`, `media_type` FROM `sky_phone_media`
WHERE `id` = ? AND %s
LIMIT 1
]]):format(condition), params)
local media = rows[1]
if not media or media.media_type ~= media_type
or type(media.url) ~= "string"
or #media.url > Config.Media.UrlMaxLength
or not media.url:match("^https://")
then
Bridge.Debug(
"warn",
"[sky_phone] Rejected unowned %s media %s from source %s.",
media_type,
tostring(media_id),
tostring(source)
)
return nil, "invalid_attachment"
end
return media.url
end
local function upload_result(source, correlation_id, success, error_code, media)
TriggerClientEvent("sky_phone:media:upload-result", source, {
correlationId = correlation_id,
@@ -268,7 +307,7 @@ local function await_giphy_http(url)
status = status,
})
end, "GET", "", {})
return Await(request)
return Citizen.Await(request)
end
local function parse_giphy_json(value)