Files
toolbox/plugin/utility/file_hash/index.html
T
2023-09-28 16:21:06 +08:00

223 lines
9.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{extend name="common/plugin_layout" /}
{block name="title"}{$plugin.title} - {:config_get('title')}{/block}
{block name="main"}
<style>
.btn-block {
white-space:normal;
}
</style>
<div class="container-xl" id="app">
<div class="col-sm-12 col-md-10 col-xl-8 center-block">
<div class="card card-preview">
<div class="card-inner mt-3">
<div class="nya-title nk-ibx-action-item progress-rating">
<span class="nk-menu-text font-weight-bold">文件哈希计算</span>
</div>
<div class="progress progress-lg mt-1 mb-1">
<div class="progress-bar progress-bar-striped progress-bar-animated" v-bind:style="{ width: progress + '%' }">{{progress}}%</div>
</div>
<div class="form-group">
<label class="form-label">文件选择</label>
<div class="text-center pt-5 pb-5 btn btn-lg btn-block btn-outline-light mb-4 d-block">
<div class="preview-icon-wrap"><em class="ni ni-upload"></em></div><span>拖拽文件到这里或者点击选择文件</span>
<input type="file" id="file" multiple="multiple" style="opacity: 0;position: absolute;cursor: pointer;width: 100%;height: 100%;left: 0;top: 0;" @change="selectFile">
</div>
</div>
<div class="form-group">
<label class="form-label">生成选项:</label>
<div class="form-control-wrap">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customCheck1" v-model="set.md5"><label class="custom-control-label" for="customCheck1">MD5</label>
</div>
<div class="custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="customCheck2" v-model="set.sha1"><label class="custom-control-label" for="customCheck2">SHA1</label>
</div>
<div class="custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="customCheck5" v-model="set.sha256"><label class="custom-control-label" for="customCheck5">SHA256</label>
</div>
<div class="custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="customCheck7" v-model="set.sha512"><label class="custom-control-label" for="customCheck7">SHA512</label>
</div>
<div class="custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="customCheck8" v-model="set.ripemd160"><label class="custom-control-label" for="customCheck8">RIPEMD160</label>
</div>
<div class="custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="customCheck9" v-model="set.crc32"><label class="custom-control-label" for="customCheck9">CRC32</label>
</div>
</div>
</div>
<div class="form-group mt-3" id="resultdiv" v-show="result">
<label class="form-label">结果:</label>
<div class="border p-2" v-html="result">
</div>
</div>
</div>
</div>
<div class="card card-preview">
<div class="card-inner">
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
<div class="accordion-inner">
<p>可同时选择多个文件计算</p>
<p>使用crypto-js 本地计算,文件不会被上传到服务器</p>
</div>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdn_cdnjs}vue/2.6.14/vue.min.js"></script>
<script src="{$cdn_cdnjs}crypto-js/4.1.1/crypto-js.min.js"></script>
<script src="/static/js/crc32.js"></script>
<script>
new Vue({
el: '#app',
data: {
set: {
md5: true,
sha1: true,
sha256: false,
sha512: false,
ripemd160: false,
crc32: false,
},
algorithms: [
'md5',
'sha1',
'sha256',
'sha512',
'ripemd160',
'crc32',
],
result: '',
progress: 0,
},
created() {
},
methods: {
swapendian32(val) {
return (((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >> 8) & 0xFF00)
| ((val >> 24) & 0xFF)) >>> 0;
},
arrayBufferToWordArray(arrayBuffer) {
var fullWords = Math.floor(arrayBuffer.byteLength / 4);
var bytesLeft = arrayBuffer.byteLength % 4;
var u32 = new Uint32Array(arrayBuffer, 0, fullWords);
var u8 = new Uint8Array(arrayBuffer);
var cp = [];
for (var i = 0; i < fullWords; ++i) {
cp.push(this.swapendian32(u32[i]));
}
if (bytesLeft) {
var pad = 0;
for (var i = bytesLeft; i > 0; --i) {
pad = pad << 8;
pad += u8[u8.byteLength - i];
}
for (var i = 0; i < 4 - bytesLeft; ++i) {
pad = pad << 8;
}
cp.push(pad);
}
return CryptoJS.lib.WordArray.create(cp, arrayBuffer.byteLength);
},
progressiveRead(file, work, done) {
return new Promise((resolve) => {
var chunkSize = 2097152; // 256KiB at a time
var pos = 0;
var reader = new FileReader();
function progressiveReadNext() {
var end = Math.min(pos + chunkSize, file.size);
reader.onload = function (e) {
pos = end;
work(e.target.result, pos, file);
if (pos < file.size) {
progressiveReadNext();
}
else {
// Done
resolve(file);
}
}
if (file.slice) {
var blob = file.slice(pos, end);
}
else if (file.webkitSlice) {
var blob = file.webkitSlice(pos, end);
}
reader.readAsArrayBuffer(blob);
}
progressiveReadNext();
})
},
async hash(file,total,id) {
var that = this;
var contents = [];
for (var v of Object.keys(this.set)) {
if (this.set[v]){
if(v == 'crc32'){
var crc32intermediate = 0;
}else{
contents[v] = CryptoJS.algo[v.toUpperCase()].create();
}
}
}
await this.progressiveRead(file, function (data, pos, file) {
var wordArray = that.arrayBufferToWordArray(data);
for (var v of Object.keys(contents)) {
contents[v].update(wordArray)
}
if(typeof crc32intermediate !== "undefined"){
crc32intermediate = crc32(new Uint8Array(data), crc32intermediate);
}
var progressRate = Math.round(pos / file.size / total * 100 + (id-1) / total * 100);
that.progress = progressRate;
});
var result = [];
for (var v of Object.keys(contents)) {
result[v] = contents[v].finalize().toString();
}
if(typeof crc32intermediate !== "undefined"){
if(crc32intermediate < 0) crc32intermediate = 0xFFFFFFFF + crc32intermediate + 1;
result['crc32'] = crc32intermediate.toString(16);
}
return result;
},
async selectFile(e) {
var total = e.target.files.length;
let loading = layer.msg('正在计算中', {icon: 16,shade: 0.1,time: 0});
let list = '';
var i = 1;
for (const file of e.target.files) {
list += `<span class="font-weight-bold text-primary">${file.name}</span>${file.size} bytes<br/>`;
await this.hash(file,total,i++).then(res => {
for (var v of Object.keys(res)) {
list += `<b>${v.toUpperCase()}</b>${res[v]}<br/>`
}
})
list += '<br/>';
}
this.result = list
layer.close(loading);
$("#file").val('');
},
reset(){
this.result = '';
this.progress = 0;
}
},
})
</script>
{/block}