perf: WebSocket 数据传输加密

This commit is contained in:
kuaifan 2023-03-31 20:24:23 +08:00
parent 60a41cae41
commit ab0a5898cb
5 changed files with 58 additions and 13 deletions

View File

@ -398,9 +398,22 @@ class Doo
} }
} }
if ($array['client_type'] === 'pgp' && $array['client_key']) { if ($array['client_type'] === 'pgp' && $array['client_key']) {
$array['client_key'] = str_replace(["-", "_", "$"], ["+", "/", "\n"], $array['client_key']); $array['client_key'] = self::pgpPublicFormat($array['client_key']);
$array['client_key'] = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" . $array['client_key'] . "\n-----END PGP PUBLIC KEY BLOCK-----";
} }
return $array; return $array;
} }
/**
* 还原公钥格式
* @param $key
* @return string
*/
public static function pgpPublicFormat($key): string
{
$key = str_replace(["-", "_", "$"], ["+", "/", "\n"], $key);
if (!str_contains($key, '-----BEGIN PGP PUBLIC KEY BLOCK-----')) {
$key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" . $key . "\n-----END PGP PUBLIC KEY BLOCK-----";
}
return $key;
}
} }

View File

@ -138,6 +138,16 @@ class WebSocketService implements WebSocketHandlerInterface
} }
} }
return; return;
/**
* 加密参数
*/
case 'encrypt':
if ($data['type'] === 'pgp') {
$data['key'] = Doo::pgpPublicFormat($data['key']);
}
Cache::put("User::encrypt:" . $frame->fd, Base::array2json($data), Carbon::now()->addDay());
return;
} }
// //
if ($msgId) { if ($msgId) {

View File

@ -6,6 +6,7 @@ namespace App\Tasks;
use App\Models\WebSocket; use App\Models\WebSocket;
use App\Models\WebSocketTmpMsg; use App\Models\WebSocketTmpMsg;
use App\Module\Base; use App\Module\Base;
use App\Module\Doo;
use Cache; use Cache;
use Carbon\Carbon; use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task; use Hhxsv5\LaravelS\Swoole\Task\Task;
@ -177,10 +178,19 @@ class PushTask extends AbstractTask
Task::deliver($task); Task::deliver($task);
} else { } else {
try { try {
$encrypt = Base::json2array(Cache::get("User::encrypt:" . $fid));
if ($encrypt['type'] == 'pgp') {
$msg = [
'type' => 'encrypt',
'encrypted' => Doo::pgpEncryptApi($msg, $encrypt['key']),
];
}
$swoole->push($fid, Base::array2json($msg)); $swoole->push($fid, Base::array2json($msg));
$tmpMsgId > 0 && WebSocketTmpMsg::whereId($tmpMsgId)->update(['send' => 1]); if ($tmpMsgId > 0) {
WebSocketTmpMsg::whereId($tmpMsgId)->update(['send' => 1]);
}
} catch (\Throwable) { } catch (\Throwable) {
// 发送失败
} }
} }
} }

View File

@ -151,7 +151,7 @@ export default {
params.data = {encrypted: await dispatch("pgpEncryptApi", params.data)} params.data = {encrypted: await dispatch("pgpEncryptApi", params.data)}
} }
} }
encrypt.push("client_type=pgp;client_key=" + $urlSafe((await dispatch("pgpGetLocalKey")).publicKeyB64)) encrypt.push("client_type=pgp;client_key=" + (await dispatch("pgpGetLocalKey")).publicKeyB64)
} }
if (encrypt.length > 0) { if (encrypt.length > 0) {
params.header.encrypt = encrypt.join(";") params.header.encrypt = encrypt.join(";")
@ -2843,11 +2843,19 @@ export default {
state.wsRandom = wsRandom; state.wsRandom = wsRandom;
// //
state.ws = new WebSocket(url); state.ws = new WebSocket(url);
state.ws.onopen = (e) => { state.ws.onopen = async (e) => {
wgLog && console.log("[WS] Open", e, $A.formatDate()) wgLog && console.log("[WS] Open", e, $A.formatDate())
state.wsOpenNum++; state.wsOpenNum++;
//
dispatch("websocketSend", {
type: 'encrypt',
data: {
type: 'pgp',
key: (await dispatch("pgpGetLocalKey")).publicKeyB64
}
})
}; };
state.ws.onclose = (e) => { state.ws.onclose = async (e) => {
wgLog && console.log("[WS] Close", e, $A.formatDate()) wgLog && console.log("[WS] Close", e, $A.formatDate())
state.ws = null; state.ws = null;
// //
@ -2856,7 +2864,7 @@ export default {
wsRandom === state.wsRandom && dispatch('websocketConnection'); wsRandom === state.wsRandom && dispatch('websocketConnection');
}, 3000); }, 3000);
}; };
state.ws.onerror = (e) => { state.ws.onerror = async (e) => {
wgLog && console.log("[WS] Error", e, $A.formatDate()) wgLog && console.log("[WS] Error", e, $A.formatDate())
state.ws = null; state.ws = null;
// //
@ -2865,9 +2873,13 @@ export default {
wsRandom === state.wsRandom && dispatch('websocketConnection'); wsRandom === state.wsRandom && dispatch('websocketConnection');
}, 3000); }, 3000);
}; };
state.ws.onmessage = (e) => { state.ws.onmessage = async (e) => {
wgLog && console.log("[WS] Message", e); wgLog && console.log("[WS] Message", e);
const msgDetail = $A.formatMsgBasic($A.jsonParse(e.data)); let result = $A.jsonParse(e.data);
if (result.type === "encrypt" && result.encrypted) {
result = await dispatch("pgpDecryptApi", result.encrypted)
}
const msgDetail = $A.formatMsgBasic(result);
const {type, msgId} = msgDetail; const {type, msgId} = msgDetail;
switch (type) { switch (type) {
case "open": case "open":
@ -3203,7 +3215,7 @@ export default {
passphrase: state.clientId, passphrase: state.clientId,
userIDs: [{name: 'doo', email: 'admin@admin.com'}], userIDs: [{name: 'doo', email: 'admin@admin.com'}],
}) })
data.publicKeyB64 = data.publicKey.replace(/\s*-----(BEGIN|END) PGP PUBLIC KEY BLOCK-----\s*/g, '').replace(/\n+/g, '$') data.publicKeyB64 = $urlSafe(data.publicKey.replace(/\s*-----(BEGIN|END) PGP PUBLIC KEY BLOCK-----\s*/g, ''))
resolve(data) resolve(data)
}) })
}, },

View File

@ -77,9 +77,9 @@ export function $callData(key, requestData, state) {
export function $urlSafe(value, encode = true) { export function $urlSafe(value, encode = true) {
if (value) { if (value) {
if (encode) { if (encode) {
value = String(value).replace(/\+/g, "-").replace(/\//g, "_") value = String(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/\n/g, '$')
} else { } else {
value = String(value).replace(/-/g, "+").replace(/_/g, "/") value = String(value).replace(/\-/g, "+").replace(/\_/g, "/").replace(/\$/g, '\n')
} }
} }
return value return value