package/package.json000644 001750 001750 0000002152 12645052711013022 0ustar00000000 000000 { "name": "abab", "version": "1.0.3", "description": "WHATWG spec-compliant implementations of window.atob and window.btoa.", "main": "index.js", "files": [ "index.js", "lib/" ], "scripts": { "mocha": "mocha test/node", "karma": "karma start", "test": "npm run lint && npm run mocha && npm run karma", "lint": "jscs . && eslint ." }, "repository": { "type": "git", "url": "git+https://github.com/jsdom/abab.git" }, "keywords": [ "atob", "btoa", "browser" ], "author": "Jeff Carpenter ", "license": "ISC", "bugs": { "url": "https://github.com/jsdom/abab/issues" }, "homepage": "https://github.com/jsdom/abab#readme", "devDependencies": { "babel-core": "^6.1.4", "babel-loader": "^6.1.0", "babel-preset-es2015": "^6.1.4", "eslint": "^1.3.1", "jscs": "^2.1.1", "karma": "^0.13.10", "karma-cli": "^0.1.1", "karma-firefox-launcher": "^0.1.6", "karma-mocha": "^0.2.0", "karma-sauce-launcher": "^0.2.14", "karma-webpack": "^1.7.0", "mocha": "^2.2.5", "webpack": "^1.12.2" } } package/README.md000644 001750 001750 0000004025 12641034053012007 0ustar00000000 000000 # abab [![npm version](https://badge.fury.io/js/abab.svg)](https://www.npmjs.com/package/abab) [![Build Status](https://travis-ci.org/jsdom/abab.svg?branch=master)](https://travis-ci.org/jsdom/abab) A module that implements `window.atob` and `window.btoa` according to the [WHATWG spec](https://html.spec.whatwg.org/multipage/webappapis.html#atob). The code is originally from [w3c/web-platform-tests](https://github.com/w3c/web-platform-tests/blob/master/html/webappapis/atob/base64.html). Compatibility: Node.js version 3+ and all major browsers (using browserify or webpack) Install with `npm`: ```sh npm install abab ``` ## API ### `btoa` (base64 encode) ```js const btoa = require('abab').btoa; btoa('Hello, world!'); // 'SGVsbG8sIHdvcmxkIQ==' ``` ### `atob` (base64 decode) ```js const atob = require('abab').atob; atob('SGVsbG8sIHdvcmxkIQ=='); // 'Hello, world!' ``` #### Valid characters [Per the spec](https://html.spec.whatwg.org/multipage/webappapis.html#atob:dom-windowbase64-btoa-3), `btoa` will accept strings "containing only characters in the range `U+0000` to `U+00FF`." If passed a string with characters above `U+00FF`, `btoa` will return `null`. If `atob` is passed a string that is not base64-valid, it will also return `null`. In both cases when `null` is returned, the spec calls for throwing a `DOMException` of type `InvalidCharacterError`. ## Browsers If you want to include just one of the methods to save bytes in your client-side code, you can `require` the desired module directly. ```js var atob = require('abab/lib/atob'); var btoa = require('abab/lib/btoa'); ``` ----- ### Checklists If you're **submitting a PR** or **deploying to npm**, please use the [checklists in CONTRIBUTING.md](https://github.com/jsdom/abab/blob/master/CONTRIBUTING.md#checklists) ### Remembering `atob` vs. `btoa` Here's a mnemonic that might be useful: if you have a plain string and want to base64 encode it, then decode it, `btoa` is what you run before (**b**efore - **b**toa), and `atob` is what you run after (**a**fter - **a**tob). package/index.js000644 001750 001750 0000000205 12641033372012174 0ustar00000000 000000 'use strict'; var atob = require('./lib/atob'); var btoa = require('./lib/btoa'); module.exports = { atob: atob, btoa: btoa }; package/CHANGELOG.md000644 001750 001750 0000000470 12645052522012346 0ustar00000000 000000 ## 1.0.3 - Replaced `let` with `var` in `lib/btoa.js` - Follow up from `1.0.2` - Resolves https://github.com/jsdom/abab/issues/18 ## 1.0.2 - Replaced `const` with `var` in `index.js` - Allows use of `abab` in the browser without a transpilation step - Resolves https://github.com/jsdom/abab/issues/15 package/lib/atob.js000644 001750 001750 0000007653 12604552076012604 0ustar00000000 000000 'use strict'; /** * Implementation of atob() according to the HTML spec, except that instead of * throwing INVALID_CHARACTER_ERR we return null. */ function atob(input) { // WebIDL requires DOMStrings to just be converted using ECMAScript // ToString, which in our case amounts to calling String(). input = String(input); // "Remove all space characters from input." input = input.replace(/[ \t\n\f\r]/g, ''); // "If the length of input divides by 4 leaving no remainder, then: if // input ends with one or two U+003D EQUALS SIGN (=) characters, remove // them from input." if (input.length % 4 == 0 && /==?$/.test(input)) { input = input.replace(/==?$/, ''); } // "If the length of input divides by 4 leaving a remainder of 1, throw an // INVALID_CHARACTER_ERR exception and abort these steps." // // "If input contains a character that is not in the following list of // characters and character ranges, throw an INVALID_CHARACTER_ERR // exception and abort these steps: // // U+002B PLUS SIGN (+) // U+002F SOLIDUS (/) // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9) // U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z // U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z" if (input.length % 4 == 1 || !/^[+/0-9A-Za-z]*$/.test(input)) { return null; } // "Let output be a string, initially empty." var output = ''; // "Let buffer be a buffer that can have bits appended to it, initially // empty." // // We append bits via left-shift and or. accumulatedBits is used to track // when we've gotten to 24 bits. var buffer = 0; var accumulatedBits = 0; // "While position does not point past the end of input, run these // substeps:" for (var i = 0; i < input.length; i++) { // "Find the character pointed to by position in the first column of // the following table. Let n be the number given in the second cell of // the same row." // // "Append to buffer the six bits corresponding to number, most // significant bit first." // // atobLookup() implements the table from the spec. buffer <<= 6; buffer |= atobLookup(input[i]); // "If buffer has accumulated 24 bits, interpret them as three 8-bit // big-endian numbers. Append the three characters with code points // equal to those numbers to output, in the same order, and then empty // buffer." accumulatedBits += 6; if (accumulatedBits == 24) { output += String.fromCharCode((buffer & 0xff0000) >> 16); output += String.fromCharCode((buffer & 0xff00) >> 8); output += String.fromCharCode(buffer & 0xff); buffer = accumulatedBits = 0; } // "Advance position by one character." } // "If buffer is not empty, it contains either 12 or 18 bits. If it // contains 12 bits, discard the last four and interpret the remaining // eight as an 8-bit big-endian number. If it contains 18 bits, discard the // last two and interpret the remaining 16 as two 8-bit big-endian numbers. // Append the one or two characters with code points equal to those one or // two numbers to output, in the same order." if (accumulatedBits == 12) { buffer >>= 4; output += String.fromCharCode(buffer); } else if (accumulatedBits == 18) { buffer >>= 2; output += String.fromCharCode((buffer & 0xff00) >> 8); output += String.fromCharCode(buffer & 0xff); } // "Return output." return output; } /** * A lookup table for atob(), which converts an ASCII character to the * corresponding six-bit number. */ function atobLookup(chr) { if (/[A-Z]/.test(chr)) { return chr.charCodeAt(0) - 'A'.charCodeAt(0); } if (/[a-z]/.test(chr)) { return chr.charCodeAt(0) - 'a'.charCodeAt(0) + 26; } if (/[0-9]/.test(chr)) { return chr.charCodeAt(0) - '0'.charCodeAt(0) + 52; } if (chr == '+') { return 62; } if (chr == '/') { return 63; } // Throw exception; should not be hit in tests } module.exports = atob; package/lib/btoa.js000644 001750 001750 0000003314 12645052132012563 0ustar00000000 000000 'use strict'; /** * btoa() as defined by the HTML5 spec, which mostly just references RFC4648. */ function btoa(s) { var i; // String conversion as required by WebIDL. s = String(s); // "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the // method's first argument contains any character whose code point is // greater than U+00FF." for (i = 0; i < s.length; i++) { if (s.charCodeAt(i) > 255) { return null; } } var out = ''; for (i = 0; i < s.length; i += 3) { var groupsOfSix = [undefined, undefined, undefined, undefined]; groupsOfSix[0] = s.charCodeAt(i) >> 2; groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4; if (s.length > i + 1) { groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4; groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2; } if (s.length > i + 2) { groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6; groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f; } for (var j = 0; j < groupsOfSix.length; j++) { if (typeof groupsOfSix[j] == 'undefined') { out += '='; } else { out += btoaLookup(groupsOfSix[j]); } } } return out; } /** * Lookup table for btoa(), which converts a six-bit number into the * corresponding ASCII character. */ function btoaLookup(idx) { if (idx < 26) { return String.fromCharCode(idx + 'A'.charCodeAt(0)); } if (idx < 52) { return String.fromCharCode(idx - 26 + 'a'.charCodeAt(0)); } if (idx < 62) { return String.fromCharCode(idx - 52 + '0'.charCodeAt(0)); } if (idx == 62) { return '+'; } if (idx == 63) { return '/'; } // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests. } module.exports = btoa;