has anyone used any PGP Libraries in suitescript t...
# suitescript
j
has anyone used any PGP Libraries in suitescript to decrypt PGP Messages?
b
https://openpgpjs.org/ just barely works in 2.1 if you are willing to shim a bunch of globals that it expects to be present
dont expect performance to be great
j
that's currently what I'm doing, but with version 3.1.2
banging my head against the wall lol
2.1 works tho? @battk I went back to 3.1.2 because that was the last version that would support v3 of the PGP Private key
b
suitescript 2.1
j
ahh, got it
b
you need to add shims for the global self, navigator.userAgent, crypto.getRandomValues, atob, and btoa
j
have you tested this on a server side script?
b
yes, its also why i know why Promises work serverside
since openpgp uses promises
j
do you have an example script handy? just curious how you set it up
, '../_lib/openpgp.ns', '../_lib/openpgp.worker'
i have those in the dependecies and then in the code
openpgp.config.ignore_mdc_error = true;
openpgp.initWorker({worker: openpgpworker})
// openpgp.config.debug = true;
var privKeyObject = openpgp.key.readArmored(privateKey.getContents()).keys[0];
privKeyObject.decrypt(passphrase);
var message = openpgp.message.readArmored(messageObj.getContents());
openpgp.decrypt({privateKeys: privKeyObject, message: message}).then(function (decrypted) {
log.debug('result',decrypted.data);
});
I tested it out first on just a test webserver to make sure it could decode the message, which it did, then started putting it in netsuite
b
im assuming you are getting errors about things being undefined or not functions
j
yeah, I was able to update most of them, but its asking for /asn1.js - which for some reason references the file instead of it bringing it in to the main openpgp.js file
b
dont recognize that one
i didnt use openpgp.worker
so perhaps its from there
j
hmm yeah, maybe i can get away with it not being called
b
taking a look at the source code,
Copy code
const asn1 = nodeCrypto ? require('asn1.js') : undefined;
suggests that you didnt mock the globals i mentioned required to avoid the node related code
j
how did you mock the globals? I thought that's what I had setup, but I think I might misunderstand what you were saying
b
custom module which sets things on global scope
is before the openpgp dependency so it runs first
j
I dont know if you have one handy, but so I could see an example?
b
Copy code
For example, this would setup a global navigator.userAgent
Copy code
define([], function () {
  (function () {
    this.navigator = {
      userAgent: "",
    };
  })();
});
j
I see, I was meaning more of an example of the globals you setup for openpgp
b
i have the code, but not the libraries
Copy code
define(["./getRandomValuesPolyfill.js", "./base64.js"], function (
  getRandomValuesPolyfill,
  base64
) {
  (function () {
    this.self = this;
    this.navigator = {
      userAgent: "",
    };
    this.crypto = {
      getRandomValues: getRandomValuesPolyfill,
    };
    this.atob = base64.Base64.atob;
    this.btoa = base64.Base64.btoa;
  })();

  return {};
});
not much more useful than what i shared
j
Got it, gives me something to go off of tho, thanks @battk
b
what were you using?
j
At the top of the file, I brought in a script that has these defined
Copy code
Uint8Array
so that it could be used in the rest of the script
b
you shouldnt need those in 2.1
j
ah gotcha, maybe I'll make it in 2.1 and see if it will get further without as many issues
w
Ahhh, same thing I wrestled with. (and battk helped me alot then) Here's some starters if you haven't already got it working. Suitelet:
Copy code
/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 */
define(['N/log','N/runtime','N/file','N/search','N/record','./lib/shim.js','./lib/openpgp.js'],
    /**
     *
     * @param log
     * @param runtime
     * @param file
     * @param search
     * @param record
     * @param shim
     * @param openpgp
     * @return {{onRequest: onRequest}}
     */
    function (log, runtime,file,search, record, shim, openpgp){

        async function test(fileString){
			let logmsg = '';
            let logmsgs = [];
            const publicKeyArmored = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP.js v4.5.2
Comment: <https://openpgpjs.org>

xk0EX4s+JQECALHyDkjtRrB9nvc5DD6Swdyi0rQc/x3Yxt6iP08OUt+UimkG
jfAP/LmwTi5DrhLviE98fiDBzRljjb5zLS7rtJMAEQEAAc0UYmlsbCA8Ymls
bEBob21lLmNvbT7CdQQQAQgAHwUCX4s+JQYLCQcIAwIEFQgKAgMWAgECGQEC
GwMCHgEACgkQ1Y9hTVbPxV3RoAH+MqJq9OSfW+n9vVrzSfSHiF3sTN08T2o8
xU9tz4yEOuEdmVLZdrzFGYm5XyI7VO9UEhiqkKXCMRrg/EQli9yysM5NBF+L
PiUBAf9ViMyeyYldp3puNUqdCFXEJiFGKqpk05X264gwAtJ1soNFZ1OJtr0J
N6yPl4g/io+T8bw9F2We4RxpsgUImn0jABEBAAHCXwQYAQgACQUCX4s+JQIb
DAAKCRDVj2FNVs/FXbUQAgCvCuHeJW7sag4rjQE0Nn7AV0Hhrlha7QLbu9BC
kTVZ7e8arsNUbLTixF3T7+uLYaxMzRhxBMeiJxqIdk1hIPa/
=F5HS
-----END PGP PUBLIC KEY BLOCK-----`;
            const privateKeyArmored = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.5.2
Comment: <https://openpgpjs.org>

xcBmBF+LPiUBAgCx8g5I7UawfZ73OQw+ksHcotK0HP8d2Mbeoj9PDlLflIpp
Bo3wD/y5sE4uQ64S74hPfH4gwc0ZY42+cy0u67STABEBAAH+CQMIbOGq4B5I
BqXg/S2xufEamp8ZQ0FwLFeeYDvDi0mbS0w9yNKmc5Fc3SmD7wtUupckqNEO
xWdn6nmEUXRGPLEtgae1GJvC5EbS60g6pmX+mq5T4L7wxqlDMd0PHFBhkcIY
C3Tn5WNdSWeBs659POYc1hAbpwIEK7LkDz0KwMqNXV4IzlqEazsQsdVw+pgr
42Mri8sWvUIUGFOsT+fKH+RDKcyt8kzMauliAxFOxeElh9XqM7p6/BedtA0q
MBAqvD7cUVQ+Js5QE29QyQHaGWZ5ih38ndKvzRRiaWxsIDxiaWxsQGhvbWUu
Y29tPsJ1BBABCAAfBQJfiz4lBgsJBwgDAgQVCAoCAxYCAQIZAQIbAwIeAQAK
CRDVj2FNVs/FXdGgAf4yomr05J9b6f29WvNJ9IeIXexM3TxPajzFT23PjIQ6
4R2ZUtl2vMUZiblfIjtU71QSGKqQpcIxGuD8RCWL3LKwx8BmBF+LPiUBAf9V
iMyeyYldp3puNUqdCFXEJiFGKqpk05X264gwAtJ1soNFZ1OJtr0JN6yPl4g/
io+T8bw9F2We4RxpsgUImn0jABEBAAH+CQMIYi9pIyYo/3fgkCKZXkwOiRw7
cPP9hswBTo1paQHSlgnShN91E0CHMhnJYCIWifX8dR9tw8FomTCF8Xs8zLOy
bYZBwMrJM7yYfaOII83Jpop6sJpoFuuDK7vezoa+zdYTBObmuA8xuom3+6YX
y6oFsb3Pdu8TBL4H7O9vj8Be71J5+SqFmTwYbImxPpJzFIU/8M1EJATE0ImM
fxaO6t5mTd+mALO//X2c+WkGDtBvClSesgkdiBYlkyU20tc8HfejjbIejSgx
qFdleaJNvB+syz0uuNDSwl8EGAEIAAkFAl+LPiUCGwwACgkQ1Y9hTVbPxV21
EAIArwrh3iVu7GoOK40BNDZ+wFdB4a5YWu0C27vQQpE1We3vGq7DVGy04sRd
0+/ri2GsTM0YcQTHoicaiHZNYSD2vw==
=cIyF
-----END PGP PRIVATE KEY BLOCK-----`;    // encrypted private key
            const passphrase = `password`; // what the private key is encrypted with

            let t1 = new Date().getTime();
            const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored);
            await privateKey.decrypt(passphrase);
            logmsg = 'time to decrypt the private key: '+((new Date().getTime()-t1)/1000).toFixed(2)+'s';
            logmsgs.push(logmsg);
            log.audit(logmsg);
		
            t1 = new Date().getTime();
            const { data: encrypted } = await openpgp.encrypt({
                message: openpgp.message.fromText(fileString),                         // input as Message object
                publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for encryption
                privateKeys: [privateKey]                                           // for signing (optional)
            });
            logmsg = ('time to encrypt: '+((new Date().getTime()-t1)/1000).toFixed(2)+'s');
            logmsgs.push(logmsg);
            log.audit(logmsg);
            logmsg = ('encrypted message:'+encrypted); // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
            logmsgs.push(logmsg);
            log.audit('encrypt',logmsg);
          
            t1 = new Date().getTime();
            const { data: decrypted } = await openpgp.decrypt({
                message: await openpgp.message.readArmored(encrypted),              // parse armored message
                publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, // for verification (optional)
                privateKeys: [privateKey]                                           // for decryption
            });
            logmsg = ('time to decrypt: '+((new Date().getTime()-t1)/1000).toFixed(2)+'s');
            logmsgs.push(logmsg);
            log.audit(logmsg);
            logmsg = ('decrypted message:'+decrypted); // 'Hello, World!'
            logmsgs.push(logmsg);
            log.audit('decrypt',logmsg);
          
            return logmsgs;
        }


        async function mainAsyncExecution(scriptContext){
            await log.debug(arguments.callee.name + ' start');
            let ret = await test('Hello, World!');
            return ret;
        }

        /**
         * Defines the Suitelet script trigger point.
         * @param {Object} scriptContext
         * @param {ServerRequest} scriptContext.request - Incoming request
         * @param {ServerResponse} scriptContext.response - Suitelet response
         * @since 2015.2
         */
        function onRequest(scriptContext){
            log.audit('start script');
            mainAsyncExecution().then(function (result) {
                log.audit(result);
                let output = '';
                result.forEach(function(logmsg){
                 	output += (logmsg + '\n');
                });
                scriptContext.response.write(output);
            })
                .catch(function (e) {
                log.error("e", e);
                log.error("e.stack", e.stack);
            });

        }
        return {onRequest: onRequest};
    });
shim.js:
Copy code
define(["./getRandomValuesPolyfill.js", "./base64.js"], function(getRandomValuesPolyfill, base64) {
        (function() {
                //this.window = this;
                this.self = this;
                this.navigator = {
                        userAgent: ""
                };
                this.crypto = {
                        getRandomValues: getRandomValuesPolyfill
                };
                this.atob = base64.atob;
                this.btoa = base64.btoa;
        })()
        return {}
})
getRandomValuesPolyfill.js:
Copy code
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i;((i="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).polyfillCrypto||(i.polyfillCrypto={})).getrandomvalues=t()}}((function(){return function t(i,n,s){function r(h,o){if(!n[h]){if(!i[h]){var m="function"==typeof require&&require;if(!o&&m)return m(h,!0);if(e)return e(h,!0);var f=new Error("Cannot find module '"+h+"'");throw f.code="MODULE_NOT_FOUND",f}var u=n[h]={exports:{}};i[h][0].call(u.exports,(function(t){return r(i[h][1][t]||t)}),u,u.exports,t,i,n,s)}return n[h].exports}for(var e="function"==typeof require&&require,h=0;h<s.length;h++)r(s[h]);return r}({1:[function(t,i,n){var s=new(t("mersenne-twister"))(Math.random()*Number.MAX_SAFE_INTEGER);i.exports=function(t){var i=t.length;for(;i--;)t[i]=Math.floor(256*s.random());return t}},{"mersenne-twister":2}],2:[function(t,i,n){var s=function(t){null==t&&(t=(new Date).getTime()),this.N=624,this.M=397,this.MATRIX_A=2567483615,this.UPPER_MASK=2147483648,this.LOWER_MASK=2147483647,this.mt=new Array(this.N),this.mti=this.N+1,t.constructor==Array?this.init_by_array(t,t.length):this.init_seed(t)};s.prototype.init_seed=function(t){for(this.mt[0]=t>>>0,this.mti=1;this.mti<this.N;this.mti++){t=this.mt[this.mti-1]^this.mt[this.mti-1]>>>30;this.mt[this.mti]=(1812433253*((4294901760&t)>>>16)<<16)+1812433253*(65535&t)+this.mti,this.mt[this.mti]>>>=0}},s.prototype.init_by_array=function(t,i){var n,s,r;for(this.init_seed(19650218),n=1,s=0,r=this.N>i?this.N:i;r;r--){var e=<http://this.mt[n-1]^this.mt[n-1]>>>30;this.mt[n]=(this.mt[n]^(1664525*((4294901760&e)>>>16)<<16)+1664525*(65535&e))+t[s]+s,this.mt[n]>>>=0,s++,++n>=this.N&&(this.mt[0]=this.mt[this.N-1],n=1),s>=i&&(s=0)|this.mt[n-1]^this.mt[n-1]>>>30;this.mt[n]=(this.mt[n]^(1664525*((4294901760&e)>>>16)<<16)+1664525*(65535&e))+t[s]+s,this.mt[n]>>>=0,s++,++n>=this.N&&(this.mt[0]=this.mt[this.N-1],n=1),s>=i&&(s=0)>}for(r=this.N-1;r;r--){e=<http://this.mt[n-1]^this.mt[n-1]>>>30;this.mt[n]=(this.mt[n]^(1566083941*((4294901760&e)>>>16)<<16)+1566083941*(65535&e))-n,this.mt[n]>>>=0,++n>=this.N&&(this.mt[0]=this.mt[this.N-1],n=1)|this.mt[n-1]^this.mt[n-1]>>>30;this.mt[n]=(this.mt[n]^(1566083941*((4294901760&e)>>>16)<<16)+1566083941*(65535&e))-n,this.mt[n]>>>=0,++n>=this.N&&(this.mt[0]=this.mt[this.N-1],n=1)>}<http://this.mt[0]=2147483648},s.prototype.random_int=function(){var|this.mt[0]=2147483648},s.prototype.random_int=function(){var> t,i=new Array(0,this.MATRIX_A);if(this.mti>=this.N){var n;for(this.mti==this.N+1&&this.init_seed(5489),n=0;n<this.N-this.M;n++)t=this.mt[n]&this.UPPER_MASK|this.mt[n+1]&this.LOWER_MASK,this.mt[n]=this.mt[n+this.M]^t>>>1^i[1&t];for(;n<this.N-1;n++)t=this.mt[n]&this.UPPER_MASK|this.mt[n+1]&this.LOWER_MASK,this.mt[n]=this.mt[n+(this.M-this.N)]^t>>>1^i[1&t];t=<http://this.mt[this.N-1]&this.UPPER_MASK%7Cthis.mt[0]&this.LOWER_MASK,this.mt[this.N-1]=this.mt[this.M-1]^t>>>1^i[1&t],this.mti=0}return|this.mt[this.N-1]&this.UPPER_MASK|this.mt[0]&this.LOWER_MASK,this.mt[this.N-1]=this.mt[this.M-1]^t>>>1^i[1&t],this.mti=0}return> t=<http://this.mt[this.mti++],t^=t>>>11,t^=t<<7&2636928640,t^=t<<15&4022730752,(t^=t>>>18)>>>0},s.prototype.random_int31=function(){return|this.mt[this.mti++],t^=t>>>11,t^=t<<7&2636928640,t^=t<<15&4022730752,(t^=t>>>18)>>>0},s.prototype.random_int31=function(){return> this.random_int()>>>1},s.prototype.random_incl=function(){return this.random_int()*(1/4294967295)},s.prototype.random=function(){return this.random_int()*(1/4294967296)},s.prototype.random_excl=function(){return(this.random_int()+.5)*(1/4294967296)},s.prototype.random_long=function(){return(67108864*(this.random_int()>>>5)+(this.random_int()>>>6))*(1/9007199254740992)},i.exports=s},{}]},{},[1])(1)}));
Copy code
//
// THIS FILE IS AUTOMATICALLY GENERATED! DO NOT EDIT BY HAND!
//
;(function(global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined'
        ? module.exports = factory()
        : typeof define === 'function' && define.amd
        ? define(factory) :
        // cf. <https://github.com/dankogai/js-base64/issues/119>
        (function() {
            // existing version for noConflict()
            const _Base64 = global.Base64;
            const gBase64 = factory();
            gBase64.noConflict = () => {
                global.Base64 = _Base64;
                return gBase64;
            };
            if (global.Meteor) { // Meteor.js
                Base64 = gBase64;
            }
            global.Base64 = gBase64;
        })();
}((typeof self !== 'undefined' ? self
        : typeof window !== 'undefined' ? window
        : typeof global !== 'undefined' ? global
        : this
), function() {
    'use strict';

/**
 *  base64.ts
 *
 *  Licensed under the BSD 3-Clause License.
 *    <http://opensource.org/licenses/BSD-3-Clause>
 *
 *  References:
 *    <http://en.wikipedia.org/wiki/Base64>
 *
 * @author Dan Kogai (<https://github.com/dankogai>)
 */
const version = '3.5.2';
/**
 * @deprecated use lowercase `version`.
 */
const VERSION = version;
const _hasatob = typeof atob === 'function';
const _hasbtoa = typeof btoa === 'function';
const _hasBuffer = typeof Buffer === 'function';
const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64chs = [...b64ch];
const b64tab = ((a) => {
    let tab = {};
    a.forEach((c, i) => tab[c] = i);
    return tab;
})(b64chs);
const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
const _fromCC = String.fromCharCode.bind(String);
const _U8Afrom = typeof Uint8Array.from === 'function'
    ? Uint8Array.from.bind(Uint8Array)
    : (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
const _mkUriSafe = (src) => src
    .replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_')
    .replace(/=+$/m, '');
const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
/**
 * polyfill version of `btoa`
 */
const btoaPolyfill = (bin) => {
    // console.log('polyfilled');
    let u32, c0, c1, c2, asc = '';
    const pad = bin.length % 3;
    for (let i = 0; i < bin.length;) {
        if ((c0 = bin.charCodeAt(i++)) > 255 ||
            (c1 = bin.charCodeAt(i++)) > 255 ||
            (c2 = bin.charCodeAt(i++)) > 255)
            throw new TypeError('invalid character found');
        u32 = (c0 << 16) | (c1 << 8) | c2;
        asc += b64chs[u32 >> 18 & 63]
            + b64chs[u32 >> 12 & 63]
            + b64chs[u32 >> 6 & 63]
            + b64chs[u32 & 63];
    }
    return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
};
/**
 * does what `window.btoa` of web browsers do.
 * @param {String} bin binary string
 * @returns {string} Base64-encoded string
 */
const _btoa = _hasbtoa ? (bin) => btoa(bin)
    : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64')
        : btoaPolyfill;
const _fromUint8Array = _hasBuffer
    ? (u8a) => Buffer.from(u8a).toString('base64')
    : (u8a) => {
        // cf. <https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326>
        const maxargs = 0x1000;
        let strs = [];
        for (let i = 0, l = u8a.length; i < l; i += maxargs) {
            strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
        }
        return _btoa(strs.join(''));
    };
/**
 * converts a Uint8Array to a Base64 string.
 * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5
 * @returns {string} Base64 string
 */
const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
// This trick is found broken <https://github.com/dankogai/js-base64/issues/130>
// const utob = (src: string) => unescape(encodeURIComponent(src));
// reverting good old fationed regexp
const cb_utob = (c) => {
    if (c.length < 2) {
        var cc = c.charCodeAt(0);
        return cc < 0x80 ? c
            : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))
                + _fromCC(0x80 | (cc & 0x3f)))
                : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))
                    + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
                    + _fromCC(0x80 | (cc & 0x3f)));
    }
    else {
        var cc = 0x10000
            + (c.charCodeAt(0) - 0xD800) * 0x400
            + (c.charCodeAt(1) - 0xDC00);
        return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))
            + _fromCC(0x80 | ((cc >>> 12) & 0x3f))
            + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
            + _fromCC(0x80 | (cc & 0x3f)));
    }
};
const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
/**
 * @deprecated should have been internal use only.
 * @param {string} src UTF-8 string
 * @returns {string} UTF-16 string
 */
const utob = (u) => u.replace(re_utob, cb_utob);
//
const _encode = _hasBuffer
    ? (s) => Buffer.from(s, 'utf8').toString('base64')
    : _TE
        ? (s) => _fromUint8Array(_TE.encode(s))
        : (s) => _btoa(utob(s));
/**
 * converts a UTF-8-encoded string to a Base64 string.
 * @param {boolean} [urlsafe] if `true` make the result URL-safe
 * @returns {string} Base64 string
 */
const encode = (src, urlsafe = false) => urlsafe
    ? _mkUriSafe(_encode(src))
    : _encode(src);
/**
 * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.
 * @returns {string} Base64 string
 */
const encodeURI = (src) => encode(src, true);
// This trick is found broken <https://github.com/dankogai/js-base64/issues/130>
// const btou = (src: string) => decodeURIComponent(escape(src));
// reverting good old fationed regexp
const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
const cb_btou = (cccc) => {
    switch (cccc.length) {
        case 4:
            var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
                | ((0x3f & cccc.charCodeAt(1)) << 12)
                | ((0x3f & cccc.charCodeAt(2)) << 6)
                | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;
            return (_fromCC((offset >>> 10) + 0xD800)
                + _fromCC((offset & 0x3FF) + 0xDC00));
        case 3:
            return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)
                | ((0x3f & cccc.charCodeAt(1)) << 6)
                | (0x3f & cccc.charCodeAt(2)));
        default:
            return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)
                | (0x3f & cccc.charCodeAt(1)));
    }
};
/**
 * @deprecated should have been internal use only.
 * @param {string} src UTF-16 string
 * @returns {string} UTF-8 string
 */
const btou = (b) => b.replace(re_btou, cb_btou);
/**
 * polyfill version of `atob`
 */
const atobPolyfill = (asc) => {
    // console.log('polyfilled');
    asc = asc.replace(/\s+/g, '');
    if (!b64re.test(asc))
        throw new TypeError('malformed base64.');
    asc += '=='.slice(2 - (asc.length & 3));
    let u24, bin = '', r1, r2;
    for (let i = 0; i < asc.length;) {
        u24 = b64tab[asc.charAt(i++)] << 18
            | b64tab[asc.charAt(i++)] << 12
            | (r1 = b64tab[asc.charAt(i++)]) << 6
            | (r2 = b64tab[asc.charAt(i++)]);
        bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)
            : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)
                : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
    }
    return bin;
};
/**
 * does what `window.atob` of web browsers do.
 * @param {String} asc Base64-encoded string
 * @returns {string} binary string
 */
const _atob = _hasatob ? (asc) => atob(_tidyB64(asc))
    : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary')
        : atobPolyfill;
//
const _toUint8Array = _hasBuffer
    ? (a) => _U8Afrom(Buffer.from(a, 'base64'))
    : (a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
/**
 * converts a Base64 string to a Uint8Array.
 */
const toUint8Array = (a) => _toUint8Array(_unURI(a));
//
const _decode = _hasBuffer
    ? (a) => Buffer.from(a, 'base64').toString('utf8')
    : _TD
        ? (a) => _TD.decode(_toUint8Array(a))
        : (a) => btou(_atob(a));
const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
/**
 * converts a Base64 string to a UTF-8 string.
 * @param {String} src Base64 string.  Both normal and URL-safe are supported
 * @returns {string} UTF-8 string
 */
const decode = (src) => _decode(_unURI(src));
//
const _noEnum = (v) => {
    return {
        value: v, enumerable: false, writable: true, configurable: true
    };
};
/**
 * extend String.prototype with relevant methods
 */
const extendString = function () {
    const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
    _add('fromBase64', function () { return decode(this); });
    _add('toBase64', function (urlsafe) { return encode(this, urlsafe); });
    _add('toBase64URI', function () { return encode(this, true); });
    _add('toBase64URL', function () { return encode(this, true); });
    _add('toUint8Array', function () { return toUint8Array(this); });
};
/**
 * extend Uint8Array.prototype with relevant methods
 */
const extendUint8Array = function () {
    const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
    _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); });
    _add('toBase64URI', function () { return fromUint8Array(this, true); });
    _add('toBase64URL', function () { return fromUint8Array(this, true); });
};
/**
 * extend Builtin prototypes with relevant methods
 */
const extendBuiltins = () => {
    extendString();
    extendUint8Array();
};
const gBase64 = {
    version: version,
    VERSION: VERSION,
    atob: _atob,
    atobPolyfill: atobPolyfill,
    btoa: _btoa,
    btoaPolyfill: btoaPolyfill,
    fromBase64: decode,
    toBase64: encode,
    encode: encode,
    encodeURI: encodeURI,
    encodeURL: encodeURI,
    utob: utob,
    btou: btou,
    decode: decode,
    fromUint8Array: fromUint8Array,
    toUint8Array: toUint8Array,
    extendString: extendString,
    extendUint8Array: extendUint8Array,
    extendBuiltins: extendBuiltins,
};

    //
    // export Base64 to the namespace
    //
    // ES5 is yet to have Object.assign() that may make transpilers unhappy.
    // gBase64.Base64 = Object.assign({}, gBase64);
    gBase64.Base64 = {};
    Object.keys(gBase64).forEach(k => gBase64.Base64[k] = gBase64[k]);
    return gBase64;
}));
base64.js:
j
@Watz awesome, thank you!
w
Thank @battk
👍 1
j
@Watz do you know what version of openpgp.js you're using with those examples?
w
Sorry, don't remember.
Perhaps it says in the file.. Hang on..
j
I'm trying to get an older version to work, but I think it might not be possible, running into a lot of snags. I can get the place that is sending me the files to update their encryption, worst case. Thanks for looking!
w
The file says "OpenPGP.js v4.10.8"
j
you didnt have to change anything in that file right? to get it working
w
Nope, I think I have tried both with the full version and the minified version. But I'm not 100% sure.
j
awesome, thanks for the help Tomas, I'll download that version and see if I have better results
w
Let me know if you don't get it to work. I might be able to bundle up a sdf-project.
j
I got it working! thanks @Watz - I was trying to get an older version of OpenPGP working in Netsuite because the key they were using to encrypt was from version 3, which wasnt supported in the newer version. I think the best thing now is to get them to update their key and Netsuite can use the newer version. Thank you for all the help. Been banging the keyboard for a few days now, lol Thank you @battk too, you've been a lot of help as well
w
What is the difference in the key/version?
j
the key was version 3 and what is supported is keys that are version 4 and 5