Skip to content

Commit 94a8d06

Browse files
committed
wip(wexin-dat): 新增预览支持
1 parent a2302c0 commit 94a8d06

File tree

5 files changed

+558
-255
lines changed

5 files changed

+558
-255
lines changed

examples/weixin-dat/index.html

+47-223
Original file line numberDiff line numberDiff line change
@@ -24,216 +24,10 @@
2424
<meta name="description" content="微信电脑版 dat 格式文件图片在线解密工具">
2525
<meta name="keywords" content="微信,dat,解码,解密,在线工具">
2626
<meta name="author" content="https://lzw.me">
27-
<link rel="stylesheet" href="https://npm.elemecdn.com/@fortawesome/[email protected]/css/all.min.css"
28-
crossorigin="anonymous">
29-
<link crossorigin="anonymous"
30-
integrity="sha512-SbiR/eusphKoMVVXysTKG/7VseWii+Y3FdHrt0EpKgpToZeemhqHeZeLWLhJutz/2ut2Vw1uQEj2MbRF+TVBUA=="
27+
<link rel="stylesheet" href="https://npm.elemecdn.com/@fortawesome/[email protected]/css/all.min.css" crossorigin="anonymous">
28+
<link crossorigin="anonymous" integrity="sha512-SbiR/eusphKoMVVXysTKG/7VseWii+Y3FdHrt0EpKgpToZeemhqHeZeLWLhJutz/2ut2Vw1uQEj2MbRF+TVBUA=="
3129
href="https://lib.baomitu.com/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet">
32-
<style>
33-
body,
34-
div,
35-
/* ul,
36-
ol,
37-
li, */
38-
dl,
39-
dt,
40-
dd,
41-
h1,
42-
h2,
43-
h3,
44-
p {
45-
margin: 0;
46-
padding: 0;
47-
font-style: normal;
48-
font: 14px/22px Microsoft Yahei, Arial, tahoma, Helvetica, sans-serif
49-
}
50-
51-
img {
52-
border: 0
53-
}
54-
55-
body {
56-
color: #333333;
57-
text-align: center
58-
}
59-
60-
*:focus {
61-
outline: none
62-
}
63-
64-
a {
65-
color: #252525;
66-
text-decoration: none
67-
}
68-
69-
a:hover {
70-
color: #BA2636;
71-
text-decoration: underline
72-
}
73-
74-
.a {
75-
margin: 0 auto;
76-
width: 100%;
77-
overflow: hidden
78-
}
79-
80-
.h30 {
81-
height: 30px
82-
}
83-
84-
.lf {
85-
float: left
86-
}
87-
88-
.rt {
89-
float: right
90-
}
91-
92-
.red {
93-
color: #F00
94-
}
95-
96-
h1.title {
97-
text-align: center;
98-
font-weight: bold;
99-
font-size: 32px;
100-
height: 61px;
101-
line-height: 60px;
102-
font-family: "SimHei"
103-
}
104-
105-
#header,
106-
#footer {
107-
height: 142px;
108-
margin: 0 auto;
109-
width: 782px;
110-
overflow: hidden
111-
}
112-
113-
.t1 {
114-
line-height: 30px
115-
}
116-
117-
#menu {
118-
height: 50px;
119-
line-height: 50px;
120-
text-align: left;
121-
font-size: 18px;
122-
color: #FFF
123-
}
124-
125-
#menu a {
126-
padding: 0 10px;
127-
color: #FFF
128-
}
129-
130-
h2 {
131-
text-align: left;
132-
font-size: 20px;
133-
text-indent: 10px;
134-
line-height: 40px;
135-
font-weight: bold;
136-
border: 1px solid #CCC
137-
}
138-
139-
ul.daxielist {
140-
border: 1px solid #CCC;
141-
border-top: 0;
142-
padding: 20px 0;
143-
padding-bottom: 0;
144-
display: flex;
145-
flex-wrap: wrap;
146-
overflow: hidden
147-
}
148-
149-
ul.daxielist li {
150-
float: left;
151-
width: 19.8%;
152-
min-width: 120px;
153-
font-size: 18px;
154-
padding-bottom: 10px;
155-
}
156-
157-
.main.Instructions {
158-
padding-top: 30px;
159-
text-align: center;
160-
position: relative;
161-
}
162-
163-
.stats {
164-
min-width: 100px;
165-
position: absolute;
166-
right: 18px;
167-
bottom: 10px;
168-
}
169-
170-
.Instructions,
171-
.Instructionst {
172-
border: 1px solid #CCC;
173-
padding: 10px;
174-
border-top: 0;
175-
text-align: left;
176-
font-size: 16px;
177-
line-height: 24px
178-
}
179-
180-
.Instructionst {
181-
padding-top: 0
182-
}
183-
184-
#footer {
185-
height: auto;
186-
padding: 10px 0;
187-
border-top: 2px solid #2E73D6
188-
}
189-
190-
#footer a {
191-
color: #F00
192-
}
193-
194-
.w110 {
195-
padding-left: 20px;
196-
line-height: 24px;
197-
background: url(w110.png) no-repeat 0 center
198-
}
199-
200-
p {
201-
height: 20px;
202-
}
203-
204-
.result-list {
205-
width: 100%;
206-
max-height: 1000px;
207-
overflow: auto;
208-
display: flex;
209-
flex-wrap: wrap;
210-
justify-content: center;
211-
padding: 20px;
212-
border: 1px #ccc solid;
213-
border-top-width: 0;
214-
}
215-
216-
.result-list a.r-item {
217-
width: 220px;
218-
height: 300px;
219-
margin: 5px;
220-
word-break: break-all;
221-
word-wrap: break-word;
222-
display: flex;
223-
align-items: center;
224-
justify-content: center;
225-
border: 1px rgba(200,200,200,.8) dashed;
226-
}
227-
228-
.result-list a.r-item > * {
229-
width: 100%;
230-
max-height: 100%;
231-
}
232-
233-
.footer {
234-
margin-top: 80px;
235-
}
236-
</style>
30+
<link rel="stylesheet" href="style.css?v=002">
23731
</head>
23832

23933
<body class="landing-page">
@@ -247,7 +41,7 @@
24741
<use xlink:href="#bootstrap"></use>
24842
</svg>
24943
<i class="fa fa-home bi me-2" width="40" height="32" role="img"></i>
250-
微信DAT文件解密转换器
44+
微信DAT文件解码转换器
25145
</a>
25246

25347
<ul class="nav col-12 col-lg-auto my-2 justify-content-center my-md-0 text-small">
@@ -286,15 +80,16 @@
28680
<div class="list">
28781

28882
<div class="nav-container">
289-
<h2 style="margin-top: 30px;">微信DAT文件解密转换器</h2>
83+
<h2 style="margin-top: 30px;">微信DAT文件解码转换器</h2>
29084

29185
<div class="Instructions main">
292-
29386
<div class="mb-3 row">
294-
<label for="datfiles" class="col-sm-4 col-form-label">选择 .dat 格式文件(可多选、拖动文件夹到此处)</label>
295-
<div class="col-sm-8">
296-
<input class="form-control" id="datfiles" placeholder="选择 .dat 格式文件" type="file" name="datfiles"
297-
id="datfiles" accept=".dat" multiple>
87+
<div id="convert-button-container">
88+
<span class="btn btn-primary fileinput-button">
89+
<i class="fa-solid fa-plus"></i>
90+
<span class="fileinput-btn-span">选择 .dat 格式文件 (支持多选、拖动文件夹到此处)</span>
91+
<input id="datfiles" type="file" name="datfiles" accept=".dat" multiple>
92+
</span>
29893
</div>
29994
</div>
30095

@@ -310,15 +105,16 @@ <h2 style="margin-top: 30px;">微信DAT文件解密转换器</h2>
310105

311106
<div class="Instructionst">
312107
<div class="a">
313-
<strong>微信DAT文件解密转换器使用说明</strong><br>
108+
<strong>微信DAT文件解码转换器使用说明</strong><br>
314109
<ol>
315110
<li>微信电脑版中聊天发送和接收的照片等文件,可以在 <code>WeChat Files\[微信号]\data\</code>
316111
<code>WeChat Files\[微信号]\FileStorage\MsgAttach</code> 等目录下找到。但是里面的文件全是以 <code>.dat</code>
317-
格式为后缀,这是微信编码加密后的文件,无法直接查看。</li>
318-
<li>解密:利用本页面提供的工具,可以对这类文件进行解密并展示,你也可以下载它们。</li>
112+
格式为后缀,这是微信编码加密后的文件,无法直接查看。
113+
</li>
114+
<li>解码:利用本页面提供的工具,可以对这类文件进行解密并展示,你也可以下载它们。</li>
319115
<li>便捷:你可以点击文件选择框选择多个 dat 文件,也可以直接从文件夹拖动 dat 文件至该处。解密后的结果显示在下方。</li>
320116
<li>安全:所有的操作都是在浏览器中完成的,不会上传到远程服务器。</li>
321-
<li>下载:点击图片可直接下载至浏览器默认文件下载保存的路径</li>
117+
<li>下载:点击图片下载按钮,可直接下载至浏览器默认文件下载保存的路径</li>
322118
</ul>
323119
</div>
324120
</div>
@@ -329,6 +125,35 @@ <h2 style="margin-top: 30px;">微信DAT文件解密转换器</h2>
329125
</div><!--//container-->
330126
</section><!--//cards-section-->
331127
</div><!--//page-wrapper-->
128+
<div id="preview" class="preview hide ">
129+
<div class="preview-main"></div>
130+
131+
<div class="preview-close">
132+
<i class="fa fa-close"></i>
133+
</div>
134+
135+
<div class="preview-pre">
136+
<i class="fa-solid fa-chevron-left"></i>
137+
</div>
138+
<div class="preview-next">
139+
<i class="fa-solid fa-chevron-right"></i>
140+
</div>
141+
142+
<div class="preview-footer">
143+
<div class="preview-line">
144+
<label for="">名称:</label>
145+
<span class="item-name"></span>
146+
</div>
147+
<div class="preview-line">
148+
<label for="">大小:</label>
149+
<span class="item-size"></span>
150+
</div>
151+
<div class="preview-line">
152+
<label for="">路径:</label>
153+
<span class="item-path"></span>
154+
</div>
155+
</div>
156+
</div>
332157

333158
<footer class="footer text-center">
334159
<div class="container">
@@ -341,14 +166,13 @@ <h2 style="margin-top: 30px;">微信DAT文件解密转换器</h2>
341166
</footer><!--//footer-->
342167

343168
<!-- <script crossorigin="anonymous" src="https://npm.elemecdn.com/jquery@3/dist/jquery.min.js"></script> -->
344-
<script src="https://npm.elemecdn.com/@fortawesome/[email protected]/js/all.min.js"
345-
crossorigin="anonymous"></script>
169+
<script src="https://npm.elemecdn.com/@fortawesome/[email protected]/js/all.min.js" crossorigin="anonymous"></script>
346170
<script crossorigin="anonymous"
347171
integrity="sha512-1/RvZTcCDEUjY/CypiMz+iqqtaoQfAITmNSJY17Myp4Ms5mdxPS5UV7iOfdZoxcGhzFbOm6sntTKJppjvuhg4g=="
348172
src="https://lib.baomitu.com/twitter-bootstrap/5.2.3/js/bootstrap.min.js"></script>
349173
<script src="https://lzw.me/x/lib/utils/h5-common.js"></script>
350174

351-
<script type="module" src="dist/web.main.js?v=230804-1"></script>
175+
<script type="module" src="dist/web.main.js?v=002"></script>
352176
</body>
353177

354178
</html>

examples/weixin-dat/src/utils.ts

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,41 @@
11
import { ALL_FILE_TYPE } from './constants.js';
22

3+
export function getExt(filename: string) {
4+
const [, ext] = String(filename).match(/\.([^.]+)$/) || [];
5+
return ext;
6+
}
7+
38
export function getDatType(content: Buffer, filepath = '') {
49
const [c1, c2, c3] = content;
510
const v: number[] = [0, 0, 0];
611

7-
for (const [head, ext] of Object.entries(ALL_FILE_TYPE)) {
12+
for (let [head, ext] of Object.entries(ALL_FILE_TYPE)) {
813
v[0] = c1 ^ parseInt(head.slice(0, 2), 16);
914
v[1] = c2 ^ parseInt(head.slice(2, 4), 16);
1015
v[2] = c3 ^ parseInt(head.slice(4, 6), 16);
1116

12-
if (v[0] === v[1] && v[1] === v[2]) return { ext, v };
17+
if (v[0] === v[1] && v[1] === v[2]) {
18+
const fext = getExt(filepath);
19+
if (fext && ['zip', 'mp4', 'doc'].includes(ext)) {
20+
ext = fext as any;
21+
}
22+
23+
return { ext, v };
24+
}
1325
}
1426

1527
const errmsg = `不支持的文件类型:${filepath}`;
1628
return { errmsg, ext: '', v };
1729
}
1830

1931
export function datConvert(content: Buffer, filepath = '') {
20-
const { ext, v, errmsg } = getDatType(content, filepath);
32+
let { ext, v, errmsg } = getDatType(content, filepath);
33+
const fext = getExt(filepath);
34+
35+
if (!ext) ext = fext;
2136
if (!ext && errmsg) return { ext, converted: null, errmsg };
2237

23-
const converted = filepath.endsWith(ext) ? content : content.map(d => d ^ v[0]);
38+
const converted = fext === ext ? content : content.map(d => d ^ v[0]);
2439
return { converted, ext };
2540
}
2641

@@ -45,3 +60,12 @@ export function formatByteSize(byteSize: number | string, decimal = 2, toFixed =
4560

4661
return neg + (decimal > 0 ? (toFixed ? formated.toFixed(decimal) : +formated.toFixed(decimal)) : formated) + units[idx];
4762
}
63+
64+
export async function sha256(message: string | ArrayBuffer) {
65+
if (!crypto.subtle) {
66+
return '';
67+
}
68+
if (typeof message === 'string') message = new TextEncoder().encode(message);
69+
const hash = await crypto.subtle.digest('SHA-256', message);
70+
return Array.prototype.map.call(new Uint8Array(hash), x => ('00' + x.toString(16)).slice(-2)).join('');
71+
}

0 commit comments

Comments
 (0)