image push fix
This commit is contained in:
1 parent
5b18c46ac2
commit
ef238f3b9c
2 files changed
+51
-9
No files matched your search
+18
-7
@@ -953,7 +953,15 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
if (!preg_match('/^[a-f0-9]+\.\w+$/', $fn)) continue;
|
if (!preg_match('/^[a-f0-9]+\.\w+$/', $fn)) continue;
|
||||||
$dest = $uploadDir . '/' . $fn;
|
$dest = $uploadDir . '/' . $fn;
|
||||||
if (file_exists($dest)) continue;
|
if (file_exists($dest)) continue;
|
||||||
$raw = base64_decode($att['data']);
|
// New format: HYPRCRD-RELAY-V1 envelope (decrypt-reencrypted by relay)
|
||||||
|
// Old format: raw base64(iv || cipher)
|
||||||
|
$payload = $att['data'] ?? '';
|
||||||
|
if (str_starts_with($payload, 'HYPRCRD-RELAY-V1')) {
|
||||||
|
$b64 = trim(substr($payload, strlen('HYPRCRD-RELAY-V1') + 1));
|
||||||
|
$raw = base64_decode($b64);
|
||||||
|
} else {
|
||||||
|
$raw = base64_decode($payload);
|
||||||
|
}
|
||||||
if (strlen($raw) >= 17) {
|
if (strlen($raw) >= 17) {
|
||||||
$decrypted = openssl_decrypt(substr($raw, 16), 'aes-256-cbc', $encKey, OPENSSL_RAW_DATA, substr($raw, 0, 16));
|
$decrypted = openssl_decrypt(substr($raw, 16), 'aes-256-cbc', $encKey, OPENSSL_RAW_DATA, substr($raw, 0, 16));
|
||||||
if ($decrypted !== false) file_put_contents($dest, $decrypted);
|
if ($decrypted !== false) file_put_contents($dest, $decrypted);
|
||||||
@@ -1060,7 +1068,9 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
$db->prepare("INSERT OR IGNORE INTO relay_pushed (relay_msg_id) VALUES (?)")->execute([$resData['id']]);
|
$db->prepare("INSERT OR IGNORE INTO relay_pushed (relay_msg_id) VALUES (?)")->execute([$resData['id']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload attachments (images referenced in body)
|
// Upload attachments (images referenced in body).
|
||||||
|
// Same envelope format as title/body so the relay can decrypt with
|
||||||
|
// the sender's secret and re-encrypt with the recipient's secret.
|
||||||
$cardBody = $card['body'] ?? '';
|
$cardBody = $card['body'] ?? '';
|
||||||
preg_match_all('#uploads/([a-f0-9]+\.\w+)#', $cardBody, $attMatches);
|
preg_match_all('#uploads/([a-f0-9]+\.\w+)#', $cardBody, $attMatches);
|
||||||
$uploadDir = __DIR__ . '/uploads';
|
$uploadDir = __DIR__ . '/uploads';
|
||||||
@@ -1068,13 +1078,14 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
$filePath = $uploadDir . '/' . $filename;
|
$filePath = $uploadDir . '/' . $filename;
|
||||||
if (!file_exists($filePath)) continue;
|
if (!file_exists($filePath)) continue;
|
||||||
$raw = file_get_contents($filePath);
|
$raw = file_get_contents($filePath);
|
||||||
$iv = random_bytes(16);
|
$envelope = $encryptField($raw);
|
||||||
$cipher = openssl_encrypt($raw, 'aes-256-cbc', $encKey, OPENSSL_RAW_DATA, $iv);
|
$attData = [
|
||||||
$attPayload = json_encode([
|
|
||||||
'relay_uid' => $relayUid,
|
'relay_uid' => $relayUid,
|
||||||
'filename' => $filename,
|
'filename' => $filename,
|
||||||
'data' => base64_encode($iv . $cipher),
|
'data' => $envelope,
|
||||||
]);
|
];
|
||||||
|
if ($recipient) $attData['recipient'] = $recipient;
|
||||||
|
$attPayload = json_encode($attData);
|
||||||
$ach = curl_init(rtrim($relayUrl, '/') . '/api/attachments');
|
$ach = curl_init(rtrim($relayUrl, '/') . '/api/attachments');
|
||||||
curl_setopt_array($ach, [
|
curl_setopt_array($ach, [
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
|||||||
@@ -143,18 +143,49 @@ if ($route === '/api/attachments' && $method === 'POST') {
|
|||||||
$recipient = getTenantByUsername($db, $recipientName);
|
$recipient = getTenantByUsername($db, $recipientName);
|
||||||
if (!$recipient) jsonResponse(['error' => "no such user: $recipientName"], 404);
|
if (!$recipient) jsonResponse(['error' => "no such user: $recipientName"], 404);
|
||||||
|
|
||||||
|
// Decrypt-reencrypt hop, same shape as messages: arrives encrypted with
|
||||||
|
// sender's secret, gets stored at-rest under the inter-tenant key.
|
||||||
|
if (empty($clientTenant['secret_encrypted'])) {
|
||||||
|
jsonResponse(['error' => 'sender has no client secret set — log into the relay UI and configure one in your account'], 400);
|
||||||
|
}
|
||||||
|
$senderSecret = masterDecrypt($clientTenant['secret_encrypted'], $MASTER_KEY);
|
||||||
|
if (!$senderSecret) jsonResponse(['error' => 'sender secret unavailable'], 500);
|
||||||
|
$interKey = getInterTenantKey($db, $MASTER_KEY);
|
||||||
|
if (!$interKey) jsonResponse(['error' => 'relay super-shared key not set — admin must complete setup'], 500);
|
||||||
|
|
||||||
|
$plainBytes = clientDecrypt($data, $senderSecret);
|
||||||
|
if ($plainBytes === '') jsonResponse(['error' => 'attachment decrypt failed (sender secret mismatch?)'], 400);
|
||||||
|
$storedData = clientEncrypt($plainBytes, $interKey);
|
||||||
|
|
||||||
$db->prepare('DELETE FROM attachments WHERE recipient_id = :r AND relay_uid = :uid AND filename = :fn')
|
$db->prepare('DELETE FROM attachments WHERE recipient_id = :r AND relay_uid = :uid AND filename = :fn')
|
||||||
->execute(['r' => $recipient['id'], 'uid' => $relayUid, 'fn' => $filename]);
|
->execute(['r' => $recipient['id'], 'uid' => $relayUid, 'fn' => $filename]);
|
||||||
$db->prepare('INSERT INTO attachments (recipient_id, relay_uid, filename, data) VALUES (:r, :uid, :fn, :data)')
|
$db->prepare('INSERT INTO attachments (recipient_id, relay_uid, filename, data) VALUES (:r, :uid, :fn, :data)')
|
||||||
->execute(['r' => $recipient['id'], 'uid' => $relayUid, 'fn' => $filename, 'data' => $data]);
|
->execute(['r' => $recipient['id'], 'uid' => $relayUid, 'fn' => $filename, 'data' => $storedData]);
|
||||||
jsonResponse(['ok' => true, 'id' => (int)$db->lastInsertId()]);
|
jsonResponse(['ok' => true, 'id' => (int)$db->lastInsertId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($route === '/api/attachments' && $method === 'GET') {
|
if ($route === '/api/attachments' && $method === 'GET') {
|
||||||
if (!$clientTenant) jsonResponse(['error' => 'unauthorized'], 401);
|
if (!$clientTenant) jsonResponse(['error' => 'unauthorized'], 401);
|
||||||
|
if (empty($clientTenant['secret_encrypted'])) {
|
||||||
|
jsonResponse(['error' => 'no client secret set — log into the relay UI and configure one in your account'], 400);
|
||||||
|
}
|
||||||
$relayUid = $_GET['relay_uid'] ?? '';
|
$relayUid = $_GET['relay_uid'] ?? '';
|
||||||
if (!$relayUid) jsonResponse(['error' => 'relay_uid required'], 400);
|
if (!$relayUid) jsonResponse(['error' => 'relay_uid required'], 400);
|
||||||
|
|
||||||
|
$interKey = getInterTenantKey($db, $MASTER_KEY);
|
||||||
|
if (!$interKey) jsonResponse(['error' => 'relay super-shared key not set'], 500);
|
||||||
|
$recipientSecret = masterDecrypt($clientTenant['secret_encrypted'], $MASTER_KEY);
|
||||||
|
if (!$recipientSecret) jsonResponse(['error' => 'recipient secret unavailable'], 500);
|
||||||
|
|
||||||
$stmt = $db->prepare('SELECT id, relay_uid, filename, data, created_at FROM attachments WHERE recipient_id = :r AND relay_uid = :uid');
|
$stmt = $db->prepare('SELECT id, relay_uid, filename, data, created_at FROM attachments WHERE recipient_id = :r AND relay_uid = :uid');
|
||||||
$stmt->execute(['r' => $clientTenant['id'], 'uid' => $relayUid]);
|
$stmt->execute(['r' => $clientTenant['id'], 'uid' => $relayUid]);
|
||||||
jsonResponse($stmt->fetchAll());
|
$rows = $stmt->fetchAll();
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$plainBytes = clientDecrypt($row['data'] ?? '', $interKey);
|
||||||
|
$row['data'] = clientEncrypt($plainBytes, $recipientSecret);
|
||||||
|
$out[] = $row;
|
||||||
|
}
|
||||||
|
jsonResponse($out);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user