90 lines
3.4 KiB
JavaScript
90 lines
3.4 KiB
JavaScript
import { PNG } from 'pngjs'
|
|
import fs from 'fs'
|
|
import { createHash, createPrivateKey, createSign } from 'crypto'
|
|
import { config } from './config.js'
|
|
import { server } from './index.js'
|
|
|
|
export const ImageSecurity = {
|
|
createImageHash: async (path, isCape) => {
|
|
const png = await new Promise((resolve, reject) => {
|
|
fs.createReadStream(path).pipe(new PNG()).on('metadata', function(metadata) {
|
|
if(metadata.width * metadata.height > 40960) {
|
|
reject('Image size exceeds 40960 pixels')
|
|
}
|
|
}).on('parsed', function(buff) {
|
|
resolve(this)
|
|
})
|
|
})
|
|
|
|
if (isCape) {
|
|
if(png.width % 64 === 0 && png.height % 32 === 0) {
|
|
return createHashInternal(png)
|
|
} else if (png.width % 22 === 0 && png.height % 17 === 0) {
|
|
const newPNG = new PNG({
|
|
width: Math.ceil(png.width / 22),
|
|
height: Math.ceil(png.height / 17),
|
|
})
|
|
|
|
for (let y = 0; y < png.height; y++) {
|
|
for (let x = 0; x < png.width; x++) {
|
|
const idx = (png.width * y + x) << 2
|
|
newPNG.data[idx] = png.data[idx]
|
|
newPNG.data[idx + 1] = png.data[idx + 1]
|
|
newPNG.data[idx + 2] = png.data[idx + 2]
|
|
newPNG.data[idx + 3] = png.data[idx + 3]
|
|
}
|
|
}
|
|
|
|
for (let y = png.height; y < newPNG.height; y++) {
|
|
for (let x = png.width; x < newPNG.width; x++) {
|
|
const idx = (png.width * y + x) << 2
|
|
newPNG.data[idx] = 0
|
|
newPNG.data[idx + 1] = 0
|
|
newPNG.data[idx + 2] = 0
|
|
newPNG.data[idx + 3] = 0
|
|
}
|
|
}
|
|
|
|
return createHashInternal(newPNG)
|
|
}
|
|
} else {
|
|
if(png.width % 64 === 0 && png.height % 32 === 0) {
|
|
const newPNG = new PNG({
|
|
width: png.width,
|
|
height: png.height
|
|
})
|
|
|
|
for (let y = 0; y < png.height; y++) {
|
|
for (let x = 0; x < png.width; x++) {
|
|
const idx = (png.width * y + x) << 2
|
|
newPNG.data[idx] = png.data[idx]
|
|
newPNG.data[idx + 1] = png.data[idx + 1]
|
|
newPNG.data[idx + 2] = png.data[idx + 2]
|
|
newPNG.data[idx + 3] = png.data[idx + 3]
|
|
}
|
|
}
|
|
|
|
return createHashInternal(png)
|
|
}
|
|
}
|
|
|
|
throw new Error('Invalid image size')
|
|
},
|
|
sign: async (data) => {
|
|
return createSign('RSA-SHA1').update(data).sign({ key: createPrivateKey(server.keys.privateKey) }, 'hex')
|
|
}
|
|
}
|
|
|
|
const createHashInternal = (png) => {
|
|
const hash = createHash('sha256')
|
|
for (let y = 0; y < png.height; y++) {
|
|
for (let x = 0; x < png.width; x++) {
|
|
const idx = (png.width * y + x) << 2
|
|
hash.update(png.data[idx].toString(16))
|
|
hash.update(png.data[idx + 1].toString(16))
|
|
hash.update(png.data[idx + 2].toString(16))
|
|
hash.update(png.data[idx + 3].toString(16))
|
|
}
|
|
}
|
|
return hash.digest('hex')
|
|
} |