threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
69 lines (65 loc) • 3.08 kB
text/typescript
import {aesGcmDecrypt, aesGcmEncrypt, getOrCall} from 'ts-browser-helpers'
import {makeGLBFile} from '../../utils'
import {GLTFExporter2Options} from '../export'
import {GLTFBinaryExtension} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {GLTFPreparser} from '../import'
/**
* Sample encryption processor for {@link GLTFExporter2} that wraps the glb in a new glb with encrypted content and encryption metadata.
* Uses AES-GCM ({@link aesGcmEncrypt}) for encryption since it is widely supported across browsers and js environments.
* @param gltf
* @param options
*/
export const glbEncryptionProcessor = async(gltf: ArrayBuffer|any, options: GLTFExporter2Options) => {
if (!gltf || !(gltf instanceof ArrayBuffer) || !gltf.byteLength || !options.encrypt) return gltf
if (!options.encryptKey && window && window.prompt) {
options.encryptKey = window.prompt('GLTFEncryption: Enter encryption key/password') || ''
}
if (!options.encryptKey) {
console.warn('GLTF Export: encryption key not provided, skipping encryption')
return gltf
}
const buffer = await aesGcmEncrypt(new Uint8Array(gltf), options.encryptKey)
return makeGLBFile(buffer, {
asset: {
version: '2.0',
generator: 'ThreePipeGLBWrapper',
encryption: {
type: 'aesgcm',
version: 1,
},
},
})
}
export interface IGLBEncryptionPreparser extends GLTFPreparser{
key: string | ((encryption: any, json: any, path: string)=>string|Promise<string>)
}
/**
* Sample encryption preparser for {@link GLTFLoader2} that unwraps the glb container and decrypts the content. The encryption key can be provided in the file or set in this const is prompted from the user.
*/
export const glbEncryptionPreparser: IGLBEncryptionPreparser = {
key: (encryption: any, _: any, path: string) => {
return encryption.key || window && window.prompt && window.prompt('GLTFEncryption: Please enter the password/key for the model: ' + path) || ''
},
async process(data: string | ArrayBuffer, path: string) {
if (typeof data === 'string' || data.byteLength < 100) return data
const prefixBytes = 100
const prefix = new TextDecoder().decode(new Uint8Array(data, 0, prefixBytes))
if (!prefix.includes('GLBWrapper')) return data
const binaryExtension = new GLTFBinaryExtension(data)
const json = JSON.parse(binaryExtension.content || '{}')
let data2 = binaryExtension.body || data
const encryption = json.asset?.encryption
if (!encryption) return data2
const type = encryption.type
const version = encryption.version
if (type === 'aesgcm' && version === 1) {
const key = await getOrCall(this.key, encryption, json, path) || ''
try {
data2 = (await aesGcmDecrypt(new Uint8Array(data2), key)).buffer
} catch (e) {
throw new ErrorEvent('decryption error')
}
}
return data2
},
}