├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE ├── README.md ├── angular-utf8-base64.js ├── angular-utf8-base64.min.js ├── bower.json ├── karma.conf.js ├── package.json └── test ├── .jshintrc └── angular-utf8-base64.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "curly": false, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "evil": true, 7 | "forin": true, 8 | "globalstrict": true, 9 | "immed": true, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": true, 15 | "trailing": true, 16 | "undef": true, 17 | "unused": true, 18 | 19 | "camelcase": true, 20 | "indent": 4, 21 | "quotmark": "single", 22 | 23 | "predef": [ 24 | "angular", 25 | "navigator", 26 | "module" // Require 27 | ] 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | jshint: { 7 | all: ['<%= pkg.name %>.js'], 8 | }, 9 | clean: { 10 | src: '<%= pkg.name %>.min.js' 11 | }, 12 | uglify: { 13 | main: { 14 | files: { 15 | '<%= pkg.name %>.min.js': ['<%= pkg.name %>.js'] 16 | } 17 | } 18 | }, 19 | karma: { 20 | unit: { 21 | configFile: 'karma.conf.js', 22 | singleRun: true 23 | } 24 | }, 25 | watch: { 26 | hint: { 27 | files: ['<%= pkg.name %>.js'], 28 | tasks: ['jshint'] 29 | }, 30 | test: { 31 | files: ['<%= pkg.name %>.js', 'test/**/*.spec.js'], 32 | tasks: ['karma'] 33 | } 34 | } 35 | }); 36 | 37 | grunt.loadNpmTasks('grunt-contrib-jshint'); 38 | grunt.loadNpmTasks('grunt-contrib-clean'); 39 | grunt.loadNpmTasks('grunt-contrib-watch'); 40 | grunt.loadNpmTasks('grunt-karma'); 41 | grunt.loadNpmTasks('grunt-contrib-uglify'); 42 | grunt.loadNpmTasks('grunt-notify'); 43 | 44 | grunt.registerTask('test', ['karma']); 45 | grunt.registerTask('build', ['clean', 'uglify']); 46 | grunt.registerTask('default', ['watch:test', 'watch:hint']); 47 | }; 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrey Bezyazychniy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-utf8-base64 2 | 3 | AngularJS service for UTF-8 and Base64 and Base64url Javascript Encoding 4 | 5 | angular-utf8-base64 is based on [Really fast Javascript Base64 encoder/decoder with utf-8 support](http://jsbase64.codeplex.com/releases/view/89265). I just wrapped it as AngularJS service. 6 | 7 | There is another AngularJS service for Base64 encoding [available](https://github.com/ninjatronic/angular-base64). 8 | But it doesn't support UTF-8. 9 | 10 | 11 | ## Installation 12 | 13 | ### Bower 14 | 15 | ``` 16 | bower install angular-utf8-base64 17 | ``` 18 | 19 | ```html 20 | 21 | ``` 22 | 23 | ## Usage 24 | 25 | ```javascript 26 | angular 27 | .module('myApp', ['ab-base64']) 28 | .controller('myController', [ 29 | 30 | '$scope','base64', 31 | function($scope,base64) { 32 | 33 | $scope.encoded = base64.encode('a string'); 34 | $scope.decoded = base64.decode('YSBzdHJpbmc='); 35 | }]); 36 | ``` 37 | 38 | ### Base64Url Support 39 | 40 | Commonly used for supporting JWS and JWT encodings, base64url encoding creates a URL safe output. 41 | 42 | ```javascript 43 | angular 44 | .module('myApp', ['ab-base64']) 45 | .controller('myController', [ 46 | 47 | '$scope','base64', 48 | function($scope,base64) { 49 | 50 | $scope.encoded = base64.urlencode('a string'); 51 | $scope.decoded = base64.urldecode('YSBzdHJpbmc'); 52 | }]); 53 | ``` 54 | -------------------------------------------------------------------------------- /angular-utf8-base64.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('ab-base64',[]).constant('base64', (function() { 4 | 5 | /* 6 | * Encapsulation of Vassilis Petroulias's base64.js library for AngularJS 7 | * Original notice included below 8 | */ 9 | 10 | /* 11 | Copyright Vassilis Petroulias [DRDigit] 12 | 13 | Licensed under the Apache License, Version 2.0 (the "License"); 14 | you may not use this file except in compliance with the License. 15 | You may obtain a copy of the License at 16 | 17 | http://www.apache.org/licenses/LICENSE-2.0 18 | 19 | Unless required by applicable law or agreed to in writing, software 20 | distributed under the License is distributed on an "AS IS" BASIS, 21 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | See the License for the specific language governing permissions and 23 | limitations under the License. 24 | */ 25 | var B64 = { 26 | alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', 27 | lookup: null, 28 | ie: /MSIE /.test(navigator.userAgent), 29 | ieo: /MSIE [67]/.test(navigator.userAgent), 30 | encode: function (s) { 31 | /* jshint bitwise:false */ 32 | var buffer = B64.toUtf8(s), 33 | position = -1, 34 | result, 35 | len = buffer.length, 36 | nan0, nan1, nan2, enc = [, , , ]; 37 | 38 | if (B64.ie) { 39 | result = []; 40 | while (++position < len) { 41 | nan0 = buffer[position]; 42 | nan1 = buffer[++position]; 43 | enc[0] = nan0 >> 2; 44 | enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4); 45 | if (isNaN(nan1)) 46 | enc[2] = enc[3] = 64; 47 | else { 48 | nan2 = buffer[++position]; 49 | enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6); 50 | enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63; 51 | } 52 | result.push(B64.alphabet.charAt(enc[0]), B64.alphabet.charAt(enc[1]), B64.alphabet.charAt(enc[2]), B64.alphabet.charAt(enc[3])); 53 | } 54 | return result.join(''); 55 | } else { 56 | result = ''; 57 | while (++position < len) { 58 | nan0 = buffer[position]; 59 | nan1 = buffer[++position]; 60 | enc[0] = nan0 >> 2; 61 | enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4); 62 | if (isNaN(nan1)) 63 | enc[2] = enc[3] = 64; 64 | else { 65 | nan2 = buffer[++position]; 66 | enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6); 67 | enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63; 68 | } 69 | result += B64.alphabet[enc[0]] + B64.alphabet[enc[1]] + B64.alphabet[enc[2]] + B64.alphabet[enc[3]]; 70 | } 71 | return result; 72 | } 73 | }, 74 | decode: function (s) { 75 | /* jshint bitwise:false */ 76 | s = s.replace(/\s/g, ''); 77 | if (s.length % 4) 78 | throw new Error('InvalidLengthError: decode failed: The string to be decoded is not the correct length for a base64 encoded string.'); 79 | if(/[^A-Za-z0-9+\/=\s]/g.test(s)) 80 | throw new Error('InvalidCharacterError: decode failed: The string contains characters invalid in a base64 encoded string.'); 81 | 82 | var buffer = B64.fromUtf8(s), 83 | position = 0, 84 | result, 85 | len = buffer.length; 86 | 87 | if (B64.ieo) { 88 | result = []; 89 | while (position < len) { 90 | if (buffer[position] < 128) 91 | result.push(String.fromCharCode(buffer[position++])); 92 | else if (buffer[position] > 191 && buffer[position] < 224) 93 | result.push(String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63))); 94 | else 95 | result.push(String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63))); 96 | } 97 | return result.join(''); 98 | } else { 99 | result = ''; 100 | while (position < len) { 101 | if (buffer[position] < 128) 102 | result += String.fromCharCode(buffer[position++]); 103 | else if (buffer[position] > 191 && buffer[position] < 224) 104 | result += String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63)); 105 | else 106 | result += String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63)); 107 | } 108 | return result; 109 | } 110 | }, 111 | toUtf8: function (s) { 112 | /* jshint bitwise:false */ 113 | var position = -1, 114 | len = s.length, 115 | chr, buffer = []; 116 | if (/^[\x00-\x7f]*$/.test(s)) while (++position < len) 117 | buffer.push(s.charCodeAt(position)); 118 | else while (++position < len) { 119 | chr = s.charCodeAt(position); 120 | if (chr < 128) 121 | buffer.push(chr); 122 | else if (chr < 2048) 123 | buffer.push((chr >> 6) | 192, (chr & 63) | 128); 124 | else 125 | buffer.push((chr >> 12) | 224, ((chr >> 6) & 63) | 128, (chr & 63) | 128); 126 | } 127 | return buffer; 128 | }, 129 | fromUtf8: function (s) { 130 | /* jshint bitwise:false */ 131 | var position = -1, 132 | len, buffer = [], 133 | enc = [, , , ]; 134 | if (!B64.lookup) { 135 | len = B64.alphabet.length; 136 | B64.lookup = {}; 137 | while (++position < len) 138 | B64.lookup[B64.alphabet.charAt(position)] = position; 139 | position = -1; 140 | } 141 | len = s.length; 142 | while (++position < len) { 143 | enc[0] = B64.lookup[s.charAt(position)]; 144 | enc[1] = B64.lookup[s.charAt(++position)]; 145 | buffer.push((enc[0] << 2) | (enc[1] >> 4)); 146 | enc[2] = B64.lookup[s.charAt(++position)]; 147 | if (enc[2] === 64) 148 | break; 149 | buffer.push(((enc[1] & 15) << 4) | (enc[2] >> 2)); 150 | enc[3] = B64.lookup[s.charAt(++position)]; 151 | if (enc[3] === 64) 152 | break; 153 | buffer.push(((enc[2] & 3) << 6) | enc[3]); 154 | } 155 | return buffer; 156 | } 157 | }; 158 | 159 | var B64url = { 160 | decode: function(input) { 161 | // Replace non-url compatible chars with base64 standard chars 162 | input = input 163 | .replace(/-/g, '+') 164 | .replace(/_/g, '/'); 165 | 166 | // Pad out with standard base64 required padding characters 167 | var pad = input.length % 4; 168 | if(pad) { 169 | if(pad === 1) { 170 | throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding'); 171 | } 172 | input += new Array(5-pad).join('='); 173 | } 174 | 175 | return B64.decode(input); 176 | }, 177 | 178 | encode: function(input) { 179 | var output = B64.encode(input); 180 | return output 181 | .replace(/\+/g, '-') 182 | .replace(/\//g, '_') 183 | .split('=', 1)[0]; 184 | } 185 | }; 186 | 187 | return { 188 | decode: B64.decode, 189 | encode: B64.encode, 190 | urldecode: B64url.decode, 191 | urlencode: B64url.encode, 192 | }; 193 | })()); 194 | 195 | -------------------------------------------------------------------------------- /angular-utf8-base64.min.js: -------------------------------------------------------------------------------- 1 | "use strict";angular.module("ab-base64",[]).constant("base64",function(){var a={alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",lookup:null,ie:/MSIE /.test(navigator.userAgent),ieo:/MSIE [67]/.test(navigator.userAgent),encode:function(b){var c,d,e,f,g=a.toUtf8(b),h=-1,i=g.length,j=[,,,];if(a.ie){for(c=[];++h>2,j[1]=(3&d)<<4|e>>4,isNaN(e)?j[2]=j[3]=64:(f=g[++h],j[2]=(15&e)<<2|f>>6,j[3]=isNaN(f)?64:63&f),c.push(a.alphabet.charAt(j[0]),a.alphabet.charAt(j[1]),a.alphabet.charAt(j[2]),a.alphabet.charAt(j[3]));return c.join("")}for(c="";++h>2,j[1]=(3&d)<<4|e>>4,isNaN(e)?j[2]=j[3]=64:(f=g[++h],j[2]=(15&e)<<2|f>>6,j[3]=isNaN(f)?64:63&f),c+=a.alphabet[j[0]]+a.alphabet[j[1]]+a.alphabet[j[2]]+a.alphabet[j[3]];return c},decode:function(b){if(b=b.replace(/\s/g,""),b.length%4)throw new Error("InvalidLengthError: decode failed: The string to be decoded is not the correct length for a base64 encoded string.");if(/[^A-Za-z0-9+\/=\s]/g.test(b))throw new Error("InvalidCharacterError: decode failed: The string contains characters invalid in a base64 encoded string.");var c,d=a.fromUtf8(b),e=0,f=d.length;if(a.ieo){for(c=[];f>e;)c.push(d[e]<128?String.fromCharCode(d[e++]):d[e]>191&&d[e]<224?String.fromCharCode((31&d[e++])<<6|63&d[e++]):String.fromCharCode((15&d[e++])<<12|(63&d[e++])<<6|63&d[e++]));return c.join("")}for(c="";f>e;)c+=String.fromCharCode(d[e]<128?d[e++]:d[e]>191&&d[e]<224?(31&d[e++])<<6|63&d[e++]:(15&d[e++])<<12|(63&d[e++])<<6|63&d[e++]);return c},toUtf8:function(a){var b,c=-1,d=a.length,e=[];if(/^[\x00-\x7f]*$/.test(a))for(;++cb?e.push(b):2048>b?e.push(b>>6|192,63&b|128):e.push(b>>12|224,b>>6&63|128,63&b|128);return e},fromUtf8:function(b){var c,d=-1,e=[],f=[,,,];if(!a.lookup){for(c=a.alphabet.length,a.lookup={};++d>4),f[2]=a.lookup[b.charAt(++d)],64!==f[2])&&(e.push((15&f[1])<<4|f[2]>>2),f[3]=a.lookup[b.charAt(++d)],64!==f[3]);)e.push((3&f[2])<<6|f[3]);return e}},b={decode:function(b){b=b.replace(/-/g,"+").replace(/_/g,"/");var c=b.length%4;if(c){if(1===c)throw new Error("InvalidLengthError: Input base64url string is the wrong length to determine padding");b+=new Array(5-c).join("=")}return a.decode(b)},encode:function(b){var c=a.encode(b);return c.replace(/\+/g,"-").replace(/\//g,"_").split("=",1)[0]}};return{decode:a.decode,encode:a.encode,urldecode:b.decode,urlencode:b.encode}}()); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-utf8-base64", 3 | "version": "0.0.5", 4 | "main": "angular-utf8-base64.js", 5 | "ignore": [ 6 | "package.json", 7 | "Gruntfile.js" 8 | ], 9 | "dependencies": { 10 | "angular": ">= 1.0.8" 11 | }, 12 | "devDependencies": { 13 | "angular-mocks": "~1.3.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Karma configuration 3 | // Generated on Mon Nov 03 2014 14:52:53 GMT-0700 (MST) 4 | 5 | module.exports = function(config) { 6 | config.set({ 7 | 8 | // base path that will be used to resolve all patterns (eg. files, exclude) 9 | basePath: '', 10 | 11 | 12 | // frameworks to use 13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 14 | frameworks: ['mocha', 'chai'], 15 | 16 | 17 | // list of files / patterns to load in the browser 18 | files: [ 19 | 'bower_components/angular/angular.js', 20 | 'bower_components/angular-mocks/angular-mocks.js', 21 | 'angular-utf8-base64.js', 22 | 'test/**/*.spec.js' 23 | ], 24 | 25 | 26 | // list of files to exclude 27 | exclude: [ 28 | ], 29 | 30 | 31 | // preprocess matching files before serving them to the browser 32 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 33 | preprocessors: { 34 | }, 35 | 36 | 37 | // test results reporter to use 38 | // possible values: 'dots', 'progress' 39 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 40 | reporters: ['progress'], 41 | 42 | 43 | // web server port 44 | port: 9876, 45 | 46 | 47 | // enable / disable colors in the output (reporters and logs) 48 | colors: true, 49 | 50 | 51 | // level of logging 52 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 53 | logLevel: config.LOG_INFO, 54 | 55 | 56 | // enable / disable watching file and executing tests whenever any file changes 57 | autoWatch: false, 58 | 59 | 60 | // start these browsers 61 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 62 | browsers: ['PhantomJS'], 63 | 64 | 65 | // Continuous Integration mode 66 | // if true, Karma captures browsers, runs the tests and exits 67 | singleRun: false 68 | }); 69 | }; 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-utf8-base64", 3 | "version": "0.0.5", 4 | "author": "stranger82", 5 | "description": "Base64 encoding/decoding with UTF8 support for AngularJS Apps", 6 | "contributors": [ 7 | { 8 | "name": "Andrey Bezyazychniy", 9 | "email": "stranger82@gmail.com" 10 | } 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/stranger82/angular-utf8-base64.git" 15 | }, 16 | "devDependencies": { 17 | "chai": "^1.9.2", 18 | "grunt": "^0.4.5", 19 | "grunt-contrib-clean": "^0.6.0", 20 | "grunt-contrib-jshint": "^0.10.0", 21 | "grunt-contrib-uglify": "^0.6.0", 22 | "grunt-contrib-watch": "^0.6.1", 23 | "grunt-karma": "^0.9.0", 24 | "grunt-notify": "^0.3.1", 25 | "karma": "^0.12.24", 26 | "karma-chai": "^0.1.0", 27 | "karma-mocha": "^0.1.9", 28 | "karma-phantomjs-launcher": "^0.1.4", 29 | "mocha": "^2.0.1" 30 | }, 31 | "scripts": { 32 | "test": "grunt test" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "curly": false, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "evil": true, 7 | "forin": true, 8 | "globalstrict": true, 9 | "immed": true, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": true, 15 | "trailing": true, 16 | "undef": true, 17 | "unused": true, 18 | 19 | "camelcase": true, 20 | "indent": 4, 21 | "quotmark": "single", 22 | 23 | "globals": { 24 | // Mocha 25 | "describe": false, 26 | "it": false, 27 | "before": false, 28 | "beforeEach": false, 29 | "after": false, 30 | "afterEach": false, 31 | 32 | // chai 33 | "expect": false, 34 | 35 | // angular spec 36 | "module": false, 37 | "inject": false 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/angular-utf8-base64.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var base64; 4 | 5 | beforeEach(module('ab-base64')); 6 | beforeEach(inject(function(_base64_) { 7 | base64 = _base64_; 8 | })); 9 | 10 | describe('base64 encode', function() { 11 | it('should encode simple ASCII', function() { 12 | expect(base64.encode('a string')).to.equal('YSBzdHJpbmc='); 13 | }); 14 | 15 | it('should encode data with whitespace', function() { 16 | expect(base64.encode('a string\r\ta paragraph')).to.equal('YSBzdHJpbmcNCWEgcGFyYWdyYXBo'); 17 | }); 18 | 19 | it('should encode extended utf8', function() { 20 | expect(base64.encode('I ♥ base64')).to.equal('SSDimaUgYmFzZTY0'); 21 | }); 22 | 23 | it('should encode empty data', function() { 24 | expect(base64.encode('')).to.equal(''); 25 | }); 26 | }); 27 | 28 | describe('base64 decode', function() { 29 | it('should decode simple ASCII', function() { 30 | expect(base64.decode('YSBzdHJpbmc=')).to.equal('a string'); 31 | }); 32 | 33 | it('should decode extended utf8', function() { 34 | expect(base64.decode('SSDimaUgYmFzZTY0')).to.equal('I ♥ base64'); 35 | }); 36 | 37 | it('should decode empty data', function() { 38 | expect(base64.decode('')).to.equal(''); 39 | }); 40 | 41 | it('should decode input with whitepace', function() { 42 | expect(base64.decode('YSBzd\r\t HJpbmc=')).to.equal('a string'); 43 | }); 44 | 45 | it('should throw on bad length', function() { 46 | expect(function() { base64.decode('235'); }).to.throw(/InvalidLengthError/); 47 | }); 48 | 49 | it('should throw on bad characters', function() { 50 | expect(function() { base64.decode('!$#%'); }).to.throw(/InvalidCharacterError/); 51 | }); 52 | }); 53 | 54 | describe('base64url encode', function() { 55 | it('should encode simple ASCII', function() { 56 | expect(base64.urlencode('a string')).to.equal('YSBzdHJpbmc'); 57 | }); 58 | 59 | it('should only use URL safe characters ', function() { 60 | expect(base64.urlencode('So?

I')).to.equal('U28_PHA-SQ'); 61 | }); 62 | 63 | it('should encode extended utf8', function() { 64 | expect(base64.urlencode('I ♥ me some base64url')).to.equal('SSDimaUgbWUgc29tZSBiYXNlNjR1cmw'); 65 | }); 66 | }); 67 | 68 | describe('base64url decode', function() { 69 | it('should decode simple ASCII', function() { 70 | expect(base64.urldecode('YSBzdHJpbmc')).to.equal('a string'); 71 | }); 72 | 73 | it('should decode extended utf8', function() { 74 | expect(base64.urldecode('SSDimaUgbWUgc29tZSBiYXNlNjR1cmw')).to.equal('I ♥ me some base64url'); 75 | }); 76 | 77 | it('should decode with URL safe characters ', function() { 78 | expect(base64.urldecode('U28_PHA-SQ')).to.equal('So?

I'); 79 | }); 80 | 81 | it('should throw on invalid length', function() { 82 | expect(function() { base64.urldecode('SSDim'); }).to.throw(/InvalidLengthError/); 83 | }); 84 | }); 85 | --------------------------------------------------------------------------------