K356/k356/templates/vue/plugins.js

197 lines
5.7 KiB
JavaScript

const operations = crypto.subtle
const pbkdf2_iterations = 250000
function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function arrayBufferToString(str) {
var byteArray = new Uint8Array(str);
var byteString = '';
for (var i = 0; i < byteArray.byteLength; i++) {
byteString += String.fromCodePoint(byteArray[i]);
}
return byteString;
}
function formatDate (date) {
const d = new Date(date)
const hours = d.getHours().toString().padStart(2, '0')
const minutes = d.getMinutes().toString().padStart(2, '0')
const formattedTime = `${hours}:${minutes}`
return `${d.toLocaleDateString()} ${formattedTime}`
}
const EncryptionPlugin = {
install(Vue, options) {
Vue.prototype.deriveKeyFromPassphrase = async (passphrase, salt) => {
const encoder = new TextEncoder();
const keyFromPassword = await operations.importKey(
"raw",
encoder.encode(passphrase),
"PBKDF2",
false,
["deriveKey"]
)
return await operations.deriveKey(
{
name: "PBKDF2",
salt: stringToArrayBuffer(salt),
iterations: pbkdf2_iterations,
hash: "SHA-256",
},
keyFromPassword,
{
name: "AES-GCM",
length: 256
},
true,
["wrapKey", "unwrapKey"]
)
},
Vue.prototype.generateKeyPair = async () => {
return await operations.generateKey(
{
name: "RSA-OAEP",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["encrypt", "decrypt"]
);
},
Vue.prototype.wrapKey = async (key, wrappingKey, iv) => {
return btoa(arrayBufferToString(await operations.wrapKey(
"jwk",
key,
wrappingKey,
{name: "AES-GCM", iv: stringToArrayBuffer(iv)}
)))
},
Vue.prototype.unwrapKey = async (unwrappingKey, armored_jwk_data, iv, args) => {
return await operations.unwrapKey(
"jwk",
stringToArrayBuffer(atob(armored_jwk_data)),
unwrappingKey,
{name: "AES-GCM", iv: stringToArrayBuffer(iv)},
{
name: "RSA-OAEP",
hash: "SHA-256",
},
true,
args,
)
},
Vue.prototype.encrypt = async function(data) {
return btoa(arrayBufferToString(await operations.encrypt(
{ name: "RSA-OAEP" },
this.$store.state.encryption.keyPair.publicKey,
stringToArrayBuffer(data),
)))
},
Vue.prototype.decrypt = async function(armored_data) {
return arrayBufferToString(await operations.decrypt(
{ name: "RSA-OAEP" },
this.$store.state.encryption.keyPair.privateKey,
stringToArrayBuffer(atob(armored_data))
))
},
Vue.prototype.decryptObject = async function(efields, obj) {
// Decrypt all fields and return a new object
var newobj = {}
await Promise.all(Object.keys(obj).map(async field => {
if (efields.includes(field) && obj[field] != null && obj[field] != "") {
// TODO: Catch error
newobj[field] = await this.decrypt(obj[field])
} else {
newobj[field] = obj[field]
}
}))
return newobj
},
Vue.prototype.encryptObject = async function(efields, obj) {
// Encrypt all fields and return a new object
var newobj = {}
await Promise.all(Object.keys(obj).map(async field => {
if (efields.includes(field) && obj[field] != null) {
// TODO: Catch error
newobj[field] = await this.encrypt(obj[field])
} else {
newobj[field] = obj[field]
}
}))
return newobj
},
Vue.prototype.object_edit = async function (url_edit, url_create, type, method, obj) {
let url = null
if (obj.id == undefined || obj.id == null) {
url = Urls[url_create]()
} else {
url = Urls[url_edit](obj.id)
}
const efields = this.$store.getters[`${type}/encryptedFields`]
try {
const newobj = await this.encryptObject(efields, obj)
const response = await this.$http[method](url, newobj)
if (method != "delete") {
return await this.decryptObject(efields, response.data.object)
}
} catch (err) {
let msg = "{{_('Error during edition') | escapejs}}"
if (method == "delete") {
msg = "{{_('Error during deletion') | escapejs}}"
}
Swal.fire({title: msg, icon: "error", position:"top-end", showConfirmButton: false, toast: true, timer: 1000})
throw err
}
}
}
}