├── .babelrc ├── .gitignore ├── .npmignore ├── README.md ├── bower.json ├── dist ├── angular-aws-apig.js └── angular-aws-apig.min.js ├── gulpfile.js ├── index.js ├── karma-min.conf.js ├── karma.conf.js ├── package.json ├── src ├── angular-aws-apig.js ├── lib │ ├── aws4.js │ ├── byte-length.js │ ├── hash.js │ ├── hexer.js │ └── hmac.js └── services │ └── interceptor.js └── test ├── angular-aws-apig.spec.js └── services └── interceptor.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015-ie" 4 | ], 5 | "plugins": [ 6 | "transform-object-assign" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.orig 10 | 11 | work 12 | build 13 | pids 14 | logs 15 | results 16 | coverage 17 | lib-cov 18 | html-report 19 | xunit.xml 20 | node_modules 21 | npm-debug.log 22 | 23 | .project 24 | .idea 25 | .settings 26 | .iml 27 | *.sublime-workspace 28 | *.sublime-project 29 | 30 | .DS_Store* 31 | ehthumbs.db 32 | Icon? 33 | Thumbs.db 34 | .AppleDouble 35 | .LSOverride 36 | .Spotlight-V100 37 | .Trashes 38 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Automatically ignored per: 2 | # https://www.npmjs.org/doc/developers.html#Keeping-files-out-of-your-package 3 | # 4 | # .*.swp 5 | # ._* 6 | # .DS_Store 7 | # .git 8 | # .hg 9 | # .lock-wscript 10 | # .svn 11 | # .wafpickle-* 12 | # CVS 13 | # npm-debug.log 14 | # node_modules 15 | 16 | *.seed 17 | *.log 18 | *.csv 19 | *.dat 20 | *.out 21 | *.pid 22 | *.gz 23 | *.orig 24 | 25 | work 26 | build 27 | test 28 | pids 29 | logs 30 | results 31 | coverage 32 | lib-cov 33 | html-report 34 | xunit.xml 35 | 36 | .project 37 | .idea 38 | .settings 39 | .iml 40 | *.sublime-workspace 41 | *.sublime-project 42 | 43 | ehthumbs.db 44 | Icon? 45 | Thumbs.db 46 | .AppleDouble 47 | .LSOverride 48 | .Spotlight-V100 49 | .Trashes 50 | 51 | # added by KAS 52 | test/ 53 | src/ 54 | bower_components/ 55 | babelhook.js 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-aws-apig 2 | 3 | This library provides an **Interceptor** for angular `$http` service that signs all request to **AWS APIGateway** with IAM credentials. It is handy when you use **temprorary IAM Credentials** from `AWS Cognito` or `Auth0`. Although **AWS APIGateway** provides autogenerated Javascript SDK, you can't use it with angular `$http` service and you need to regenerate it every time you change something in the API. 4 | 5 | ## Installing it 6 | 7 | You have several options: 8 | 9 | ````bash 10 | bower install angular-aws-apig --save 11 | ```` 12 | 13 | ````bash 14 | npm install angular-aws-apig --save 15 | ```` 16 | 17 | Or just include `dist/angular-aws-apig.js` or `dist/angular-aws-apig.min.js` in to your index.html 18 | 19 | ## Basic usage 20 | 21 | ````js 22 | angular.module('app', ['angular-aws-apig']) 23 | .config(function Config($httpProvider, APIGInterceptorProvider) { 24 | APIGInterceptorProvider.config({ 25 | headers: {}, 26 | region: 'us-east-1', 27 | service: 'execute-api', 28 | urlRegex: '' 29 | }) 30 | 31 | /* @ngInject */ 32 | APIGInterceptorProvider.headersGetter = function(myService, request) { 33 | myService.doSomething(); 34 | return request.headers; 35 | }; 36 | 37 | /* @ngInject */ 38 | APIGInterceptorProvider.credentialsGetter = function(store, request) { 39 | return store.get('credentials'); 40 | }; 41 | 42 | $httpProvider.interceptors.push('APIGInterceptor'); 43 | }); 44 | ```` 45 | 46 | ## APIGInterceptorProvider.config 47 | 48 | * `headers` - global headers that would be added to all api requests (default: `{}`) 49 | * `region` - AWS region (default: `us-east-1`) 50 | * `service` - AWS service (default: `execute-api`) 51 | * `urlRegex` - RegEx string, Interceptor would ignore requests to url that doesn't match this RegEx. (default: `''`) 52 | 53 | All options could be passed in `APIGInterceptorProvider.config` function as a single object or assigned directly 54 | ````js 55 | APIGInterceptorProvider.urlRegex = 'myapi.com'; 56 | ```` 57 | 58 | ## APIGInterceptorProvider.headersGetter 59 | A function that provides dynamic headers. It accepts `$http request` object as a parameter and must return `headers` object. You can pass angular dependencies in this function. 60 | 61 | ````js 62 | APIGInterceptorProvider.headersGetter = function($rootScope, request) { 63 | var headers = request.headers 64 | headers.foo = $rootScope.foo; 65 | return headers; 66 | }; 67 | ```` 68 | 69 | ## APIGInterceptorProvider.credentialsGetter 70 | A function that provides dynamic AWS IAM Credentials. It accepts `$http request` object as a parameter and must return `credentials` object. You can pass angular dependencies in this function. Function can return `$q` promise. 71 | **If this function is not specified `APIGInterceptor` will try to get credentials from `AWS.config.credentials`** 72 | 73 | ````js 74 | APIGInterceptorProvider.credentialsGetter = function(awsCredentials, auth) { 75 | return awsCredentials.get(auth.idToken); 76 | }; 77 | ```` 78 | 79 | In this example `awsCredentials.get` returns a promise that resolves with `credentials` object 80 | ````js 81 | { 82 | accessKeyId: 'accessKeyId', 83 | secretAccessKey: 'secretAccessKey', 84 | sessionToken: 'sessionToken' 85 | } 86 | ```` 87 | 88 | ## $APIGError event 89 | This event would be triggered on request error. 90 | ````js 91 | $rootScope.$on('$APIGError', (event, error) => { 92 | $log.debug(event, error); 93 | }); 94 | ```` 95 | 96 | ## Credits 97 | This library is a wrapper around [aws4](https://github.com/mhart/aws4) npm package. 98 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-aws-apig", 3 | "description": "Angular interceptor for $http service that signs all requests to AWS APIGateway with IAM credentials.", 4 | "main": "dist/angular-aws-apig.js", 5 | "authors": [ 6 | "Dmitriy Nevzorov" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "aws", 11 | "angular", 12 | "apig", 13 | "apigateway", 14 | "interceptor", 15 | "aws4", 16 | "iam" 17 | ], 18 | "moduleType": [], 19 | "homepage": "", 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ], 27 | "dependencies": { 28 | "angular": "^1.3.7" 29 | }, 30 | "devDependencies": { 31 | "angular-mocks": "^1.5.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dist/angular-aws-apig.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> 2] >>> (24 - (i % 4) * 8)) & 0xff; 227 | thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); 228 | } 229 | } else { 230 | // Copy one word at a time 231 | for (var i = 0; i < thatSigBytes; i += 4) { 232 | thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; 233 | } 234 | } 235 | this.sigBytes += thatSigBytes; 236 | 237 | // Chainable 238 | return this; 239 | }, 240 | 241 | /** 242 | * Removes insignificant bits. 243 | * 244 | * @example 245 | * 246 | * wordArray.clamp(); 247 | */ 248 | clamp: function () { 249 | // Shortcuts 250 | var words = this.words; 251 | var sigBytes = this.sigBytes; 252 | 253 | // Clamp 254 | words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); 255 | words.length = Math.ceil(sigBytes / 4); 256 | }, 257 | 258 | /** 259 | * Creates a copy of this word array. 260 | * 261 | * @return {WordArray} The clone. 262 | * 263 | * @example 264 | * 265 | * var clone = wordArray.clone(); 266 | */ 267 | clone: function () { 268 | var clone = Base.clone.call(this); 269 | clone.words = this.words.slice(0); 270 | 271 | return clone; 272 | }, 273 | 274 | /** 275 | * Creates a word array filled with random bytes. 276 | * 277 | * @param {number} nBytes The number of random bytes to generate. 278 | * 279 | * @return {WordArray} The random word array. 280 | * 281 | * @static 282 | * 283 | * @example 284 | * 285 | * var wordArray = CryptoJS.lib.WordArray.random(16); 286 | */ 287 | random: function (nBytes) { 288 | var words = []; 289 | 290 | var r = (function (m_w) { 291 | var m_w = m_w; 292 | var m_z = 0x3ade68b1; 293 | var mask = 0xffffffff; 294 | 295 | return function () { 296 | m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; 297 | m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; 298 | var result = ((m_z << 0x10) + m_w) & mask; 299 | result /= 0x100000000; 300 | result += 0.5; 301 | return result * (Math.random() > .5 ? 1 : -1); 302 | } 303 | }); 304 | 305 | for (var i = 0, rcache; i < nBytes; i += 4) { 306 | var _r = r((rcache || Math.random()) * 0x100000000); 307 | 308 | rcache = _r() * 0x3ade67b7; 309 | words.push((_r() * 0x100000000) | 0); 310 | } 311 | 312 | return new WordArray.init(words, nBytes); 313 | } 314 | }); 315 | 316 | /** 317 | * Encoder namespace. 318 | */ 319 | var C_enc = C.enc = {}; 320 | 321 | /** 322 | * Hex encoding strategy. 323 | */ 324 | var Hex = C_enc.Hex = { 325 | /** 326 | * Converts a word array to a hex string. 327 | * 328 | * @param {WordArray} wordArray The word array. 329 | * 330 | * @return {string} The hex string. 331 | * 332 | * @static 333 | * 334 | * @example 335 | * 336 | * var hexString = CryptoJS.enc.Hex.stringify(wordArray); 337 | */ 338 | stringify: function (wordArray) { 339 | // Shortcuts 340 | var words = wordArray.words; 341 | var sigBytes = wordArray.sigBytes; 342 | 343 | // Convert 344 | var hexChars = []; 345 | for (var i = 0; i < sigBytes; i++) { 346 | var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; 347 | hexChars.push((bite >>> 4).toString(16)); 348 | hexChars.push((bite & 0x0f).toString(16)); 349 | } 350 | 351 | return hexChars.join(''); 352 | }, 353 | 354 | /** 355 | * Converts a hex string to a word array. 356 | * 357 | * @param {string} hexStr The hex string. 358 | * 359 | * @return {WordArray} The word array. 360 | * 361 | * @static 362 | * 363 | * @example 364 | * 365 | * var wordArray = CryptoJS.enc.Hex.parse(hexString); 366 | */ 367 | parse: function (hexStr) { 368 | // Shortcut 369 | var hexStrLength = hexStr.length; 370 | 371 | // Convert 372 | var words = []; 373 | for (var i = 0; i < hexStrLength; i += 2) { 374 | words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); 375 | } 376 | 377 | return new WordArray.init(words, hexStrLength / 2); 378 | } 379 | }; 380 | 381 | /** 382 | * Latin1 encoding strategy. 383 | */ 384 | var Latin1 = C_enc.Latin1 = { 385 | /** 386 | * Converts a word array to a Latin1 string. 387 | * 388 | * @param {WordArray} wordArray The word array. 389 | * 390 | * @return {string} The Latin1 string. 391 | * 392 | * @static 393 | * 394 | * @example 395 | * 396 | * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); 397 | */ 398 | stringify: function (wordArray) { 399 | // Shortcuts 400 | var words = wordArray.words; 401 | var sigBytes = wordArray.sigBytes; 402 | 403 | // Convert 404 | var latin1Chars = []; 405 | for (var i = 0; i < sigBytes; i++) { 406 | var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; 407 | latin1Chars.push(String.fromCharCode(bite)); 408 | } 409 | 410 | return latin1Chars.join(''); 411 | }, 412 | 413 | /** 414 | * Converts a Latin1 string to a word array. 415 | * 416 | * @param {string} latin1Str The Latin1 string. 417 | * 418 | * @return {WordArray} The word array. 419 | * 420 | * @static 421 | * 422 | * @example 423 | * 424 | * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); 425 | */ 426 | parse: function (latin1Str) { 427 | // Shortcut 428 | var latin1StrLength = latin1Str.length; 429 | 430 | // Convert 431 | var words = []; 432 | for (var i = 0; i < latin1StrLength; i++) { 433 | words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); 434 | } 435 | 436 | return new WordArray.init(words, latin1StrLength); 437 | } 438 | }; 439 | 440 | /** 441 | * UTF-8 encoding strategy. 442 | */ 443 | var Utf8 = C_enc.Utf8 = { 444 | /** 445 | * Converts a word array to a UTF-8 string. 446 | * 447 | * @param {WordArray} wordArray The word array. 448 | * 449 | * @return {string} The UTF-8 string. 450 | * 451 | * @static 452 | * 453 | * @example 454 | * 455 | * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); 456 | */ 457 | stringify: function (wordArray) { 458 | try { 459 | return decodeURIComponent(escape(Latin1.stringify(wordArray))); 460 | } catch (e) { 461 | throw new Error('Malformed UTF-8 data'); 462 | } 463 | }, 464 | 465 | /** 466 | * Converts a UTF-8 string to a word array. 467 | * 468 | * @param {string} utf8Str The UTF-8 string. 469 | * 470 | * @return {WordArray} The word array. 471 | * 472 | * @static 473 | * 474 | * @example 475 | * 476 | * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); 477 | */ 478 | parse: function (utf8Str) { 479 | return Latin1.parse(unescape(encodeURIComponent(utf8Str))); 480 | } 481 | }; 482 | 483 | /** 484 | * Abstract buffered block algorithm template. 485 | * 486 | * The property blockSize must be implemented in a concrete subtype. 487 | * 488 | * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 489 | */ 490 | var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ 491 | /** 492 | * Resets this block algorithm's data buffer to its initial state. 493 | * 494 | * @example 495 | * 496 | * bufferedBlockAlgorithm.reset(); 497 | */ 498 | reset: function () { 499 | // Initial values 500 | this._data = new WordArray.init(); 501 | this._nDataBytes = 0; 502 | }, 503 | 504 | /** 505 | * Adds new data to this block algorithm's buffer. 506 | * 507 | * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. 508 | * 509 | * @example 510 | * 511 | * bufferedBlockAlgorithm._append('data'); 512 | * bufferedBlockAlgorithm._append(wordArray); 513 | */ 514 | _append: function (data) { 515 | // Convert string to WordArray, else assume WordArray already 516 | if (typeof data == 'string') { 517 | data = Utf8.parse(data); 518 | } 519 | 520 | // Append 521 | this._data.concat(data); 522 | this._nDataBytes += data.sigBytes; 523 | }, 524 | 525 | /** 526 | * Processes available data blocks. 527 | * 528 | * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. 529 | * 530 | * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. 531 | * 532 | * @return {WordArray} The processed data. 533 | * 534 | * @example 535 | * 536 | * var processedData = bufferedBlockAlgorithm._process(); 537 | * var processedData = bufferedBlockAlgorithm._process(!!'flush'); 538 | */ 539 | _process: function (doFlush) { 540 | // Shortcuts 541 | var data = this._data; 542 | var dataWords = data.words; 543 | var dataSigBytes = data.sigBytes; 544 | var blockSize = this.blockSize; 545 | var blockSizeBytes = blockSize * 4; 546 | 547 | // Count blocks ready 548 | var nBlocksReady = dataSigBytes / blockSizeBytes; 549 | if (doFlush) { 550 | // Round up to include partial blocks 551 | nBlocksReady = Math.ceil(nBlocksReady); 552 | } else { 553 | // Round down to include only full blocks, 554 | // less the number of blocks that must remain in the buffer 555 | nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); 556 | } 557 | 558 | // Count words ready 559 | var nWordsReady = nBlocksReady * blockSize; 560 | 561 | // Count bytes ready 562 | var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); 563 | 564 | // Process blocks 565 | if (nWordsReady) { 566 | for (var offset = 0; offset < nWordsReady; offset += blockSize) { 567 | // Perform concrete-algorithm logic 568 | this._doProcessBlock(dataWords, offset); 569 | } 570 | 571 | // Remove processed words 572 | var processedWords = dataWords.splice(0, nWordsReady); 573 | data.sigBytes -= nBytesReady; 574 | } 575 | 576 | // Return processed words 577 | return new WordArray.init(processedWords, nBytesReady); 578 | }, 579 | 580 | /** 581 | * Creates a copy of this object. 582 | * 583 | * @return {Object} The clone. 584 | * 585 | * @example 586 | * 587 | * var clone = bufferedBlockAlgorithm.clone(); 588 | */ 589 | clone: function () { 590 | var clone = Base.clone.call(this); 591 | clone._data = this._data.clone(); 592 | 593 | return clone; 594 | }, 595 | 596 | _minBufferSize: 0 597 | }); 598 | 599 | /** 600 | * Abstract hasher template. 601 | * 602 | * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) 603 | */ 604 | var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ 605 | /** 606 | * Configuration options. 607 | */ 608 | cfg: Base.extend(), 609 | 610 | /** 611 | * Initializes a newly created hasher. 612 | * 613 | * @param {Object} cfg (Optional) The configuration options to use for this hash computation. 614 | * 615 | * @example 616 | * 617 | * var hasher = CryptoJS.algo.SHA256.create(); 618 | */ 619 | init: function (cfg) { 620 | // Apply config defaults 621 | this.cfg = this.cfg.extend(cfg); 622 | 623 | // Set initial values 624 | this.reset(); 625 | }, 626 | 627 | /** 628 | * Resets this hasher to its initial state. 629 | * 630 | * @example 631 | * 632 | * hasher.reset(); 633 | */ 634 | reset: function () { 635 | // Reset data buffer 636 | BufferedBlockAlgorithm.reset.call(this); 637 | 638 | // Perform concrete-hasher logic 639 | this._doReset(); 640 | }, 641 | 642 | /** 643 | * Updates this hasher with a message. 644 | * 645 | * @param {WordArray|string} messageUpdate The message to append. 646 | * 647 | * @return {Hasher} This hasher. 648 | * 649 | * @example 650 | * 651 | * hasher.update('message'); 652 | * hasher.update(wordArray); 653 | */ 654 | update: function (messageUpdate) { 655 | // Append 656 | this._append(messageUpdate); 657 | 658 | // Update the hash 659 | this._process(); 660 | 661 | // Chainable 662 | return this; 663 | }, 664 | 665 | /** 666 | * Finalizes the hash computation. 667 | * Note that the finalize operation is effectively a destructive, read-once operation. 668 | * 669 | * @param {WordArray|string} messageUpdate (Optional) A final message update. 670 | * 671 | * @return {WordArray} The hash. 672 | * 673 | * @example 674 | * 675 | * var hash = hasher.finalize(); 676 | * var hash = hasher.finalize('message'); 677 | * var hash = hasher.finalize(wordArray); 678 | */ 679 | finalize: function (messageUpdate) { 680 | // Final message update 681 | if (messageUpdate) { 682 | this._append(messageUpdate); 683 | } 684 | 685 | // Perform concrete-hasher logic 686 | var hash = this._doFinalize(); 687 | 688 | return hash; 689 | }, 690 | 691 | blockSize: 512/32, 692 | 693 | /** 694 | * Creates a shortcut function to a hasher's object interface. 695 | * 696 | * @param {Hasher} hasher The hasher to create a helper for. 697 | * 698 | * @return {Function} The shortcut function. 699 | * 700 | * @static 701 | * 702 | * @example 703 | * 704 | * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); 705 | */ 706 | _createHelper: function (hasher) { 707 | return function (message, cfg) { 708 | return new hasher.init(cfg).finalize(message); 709 | }; 710 | }, 711 | 712 | /** 713 | * Creates a shortcut function to the HMAC's object interface. 714 | * 715 | * @param {Hasher} hasher The hasher to use in this HMAC helper. 716 | * 717 | * @return {Function} The shortcut function. 718 | * 719 | * @static 720 | * 721 | * @example 722 | * 723 | * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); 724 | */ 725 | _createHmacHelper: function (hasher) { 726 | return function (message, key) { 727 | return new C_algo.HMAC.init(hasher, key).finalize(message); 728 | }; 729 | } 730 | }); 731 | 732 | /** 733 | * Algorithm namespace. 734 | */ 735 | var C_algo = C.algo = {}; 736 | 737 | return C; 738 | }(Math)); 739 | 740 | 741 | return CryptoJS; 742 | 743 | })); 744 | },{}],2:[function(require,module,exports){ 745 | ;(function (root, factory, undef) { 746 | if (typeof exports === "object") { 747 | // CommonJS 748 | module.exports = exports = factory(require("./core"), require("./sha256"), require("./hmac")); 749 | } 750 | else if (typeof define === "function" && define.amd) { 751 | // AMD 752 | define(["./core", "./sha256", "./hmac"], factory); 753 | } 754 | else { 755 | // Global (browser) 756 | factory(root.CryptoJS); 757 | } 758 | }(this, function (CryptoJS) { 759 | 760 | return CryptoJS.HmacSHA256; 761 | 762 | })); 763 | },{"./core":1,"./hmac":3,"./sha256":4}],3:[function(require,module,exports){ 764 | ;(function (root, factory) { 765 | if (typeof exports === "object") { 766 | // CommonJS 767 | module.exports = exports = factory(require("./core")); 768 | } 769 | else if (typeof define === "function" && define.amd) { 770 | // AMD 771 | define(["./core"], factory); 772 | } 773 | else { 774 | // Global (browser) 775 | factory(root.CryptoJS); 776 | } 777 | }(this, function (CryptoJS) { 778 | 779 | (function () { 780 | // Shortcuts 781 | var C = CryptoJS; 782 | var C_lib = C.lib; 783 | var Base = C_lib.Base; 784 | var C_enc = C.enc; 785 | var Utf8 = C_enc.Utf8; 786 | var C_algo = C.algo; 787 | 788 | /** 789 | * HMAC algorithm. 790 | */ 791 | var HMAC = C_algo.HMAC = Base.extend({ 792 | /** 793 | * Initializes a newly created HMAC. 794 | * 795 | * @param {Hasher} hasher The hash algorithm to use. 796 | * @param {WordArray|string} key The secret key. 797 | * 798 | * @example 799 | * 800 | * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); 801 | */ 802 | init: function (hasher, key) { 803 | // Init hasher 804 | hasher = this._hasher = new hasher.init(); 805 | 806 | // Convert string to WordArray, else assume WordArray already 807 | if (typeof key == 'string') { 808 | key = Utf8.parse(key); 809 | } 810 | 811 | // Shortcuts 812 | var hasherBlockSize = hasher.blockSize; 813 | var hasherBlockSizeBytes = hasherBlockSize * 4; 814 | 815 | // Allow arbitrary length keys 816 | if (key.sigBytes > hasherBlockSizeBytes) { 817 | key = hasher.finalize(key); 818 | } 819 | 820 | // Clamp excess bits 821 | key.clamp(); 822 | 823 | // Clone key for inner and outer pads 824 | var oKey = this._oKey = key.clone(); 825 | var iKey = this._iKey = key.clone(); 826 | 827 | // Shortcuts 828 | var oKeyWords = oKey.words; 829 | var iKeyWords = iKey.words; 830 | 831 | // XOR keys with pad constants 832 | for (var i = 0; i < hasherBlockSize; i++) { 833 | oKeyWords[i] ^= 0x5c5c5c5c; 834 | iKeyWords[i] ^= 0x36363636; 835 | } 836 | oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; 837 | 838 | // Set initial values 839 | this.reset(); 840 | }, 841 | 842 | /** 843 | * Resets this HMAC to its initial state. 844 | * 845 | * @example 846 | * 847 | * hmacHasher.reset(); 848 | */ 849 | reset: function () { 850 | // Shortcut 851 | var hasher = this._hasher; 852 | 853 | // Reset 854 | hasher.reset(); 855 | hasher.update(this._iKey); 856 | }, 857 | 858 | /** 859 | * Updates this HMAC with a message. 860 | * 861 | * @param {WordArray|string} messageUpdate The message to append. 862 | * 863 | * @return {HMAC} This HMAC instance. 864 | * 865 | * @example 866 | * 867 | * hmacHasher.update('message'); 868 | * hmacHasher.update(wordArray); 869 | */ 870 | update: function (messageUpdate) { 871 | this._hasher.update(messageUpdate); 872 | 873 | // Chainable 874 | return this; 875 | }, 876 | 877 | /** 878 | * Finalizes the HMAC computation. 879 | * Note that the finalize operation is effectively a destructive, read-once operation. 880 | * 881 | * @param {WordArray|string} messageUpdate (Optional) A final message update. 882 | * 883 | * @return {WordArray} The HMAC. 884 | * 885 | * @example 886 | * 887 | * var hmac = hmacHasher.finalize(); 888 | * var hmac = hmacHasher.finalize('message'); 889 | * var hmac = hmacHasher.finalize(wordArray); 890 | */ 891 | finalize: function (messageUpdate) { 892 | // Shortcut 893 | var hasher = this._hasher; 894 | 895 | // Compute HMAC 896 | var innerHash = hasher.finalize(messageUpdate); 897 | hasher.reset(); 898 | var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); 899 | 900 | return hmac; 901 | } 902 | }); 903 | }()); 904 | 905 | 906 | })); 907 | },{"./core":1}],4:[function(require,module,exports){ 908 | ;(function (root, factory) { 909 | if (typeof exports === "object") { 910 | // CommonJS 911 | module.exports = exports = factory(require("./core")); 912 | } 913 | else if (typeof define === "function" && define.amd) { 914 | // AMD 915 | define(["./core"], factory); 916 | } 917 | else { 918 | // Global (browser) 919 | factory(root.CryptoJS); 920 | } 921 | }(this, function (CryptoJS) { 922 | 923 | (function (Math) { 924 | // Shortcuts 925 | var C = CryptoJS; 926 | var C_lib = C.lib; 927 | var WordArray = C_lib.WordArray; 928 | var Hasher = C_lib.Hasher; 929 | var C_algo = C.algo; 930 | 931 | // Initialization and round constants tables 932 | var H = []; 933 | var K = []; 934 | 935 | // Compute constants 936 | (function () { 937 | function isPrime(n) { 938 | var sqrtN = Math.sqrt(n); 939 | for (var factor = 2; factor <= sqrtN; factor++) { 940 | if (!(n % factor)) { 941 | return false; 942 | } 943 | } 944 | 945 | return true; 946 | } 947 | 948 | function getFractionalBits(n) { 949 | return ((n - (n | 0)) * 0x100000000) | 0; 950 | } 951 | 952 | var n = 2; 953 | var nPrime = 0; 954 | while (nPrime < 64) { 955 | if (isPrime(n)) { 956 | if (nPrime < 8) { 957 | H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); 958 | } 959 | K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); 960 | 961 | nPrime++; 962 | } 963 | 964 | n++; 965 | } 966 | }()); 967 | 968 | // Reusable object 969 | var W = []; 970 | 971 | /** 972 | * SHA-256 hash algorithm. 973 | */ 974 | var SHA256 = C_algo.SHA256 = Hasher.extend({ 975 | _doReset: function () { 976 | this._hash = new WordArray.init(H.slice(0)); 977 | }, 978 | 979 | _doProcessBlock: function (M, offset) { 980 | // Shortcut 981 | var H = this._hash.words; 982 | 983 | // Working variables 984 | var a = H[0]; 985 | var b = H[1]; 986 | var c = H[2]; 987 | var d = H[3]; 988 | var e = H[4]; 989 | var f = H[5]; 990 | var g = H[6]; 991 | var h = H[7]; 992 | 993 | // Computation 994 | for (var i = 0; i < 64; i++) { 995 | if (i < 16) { 996 | W[i] = M[offset + i] | 0; 997 | } else { 998 | var gamma0x = W[i - 15]; 999 | var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ 1000 | ((gamma0x << 14) | (gamma0x >>> 18)) ^ 1001 | (gamma0x >>> 3); 1002 | 1003 | var gamma1x = W[i - 2]; 1004 | var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ 1005 | ((gamma1x << 13) | (gamma1x >>> 19)) ^ 1006 | (gamma1x >>> 10); 1007 | 1008 | W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; 1009 | } 1010 | 1011 | var ch = (e & f) ^ (~e & g); 1012 | var maj = (a & b) ^ (a & c) ^ (b & c); 1013 | 1014 | var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); 1015 | var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); 1016 | 1017 | var t1 = h + sigma1 + ch + K[i] + W[i]; 1018 | var t2 = sigma0 + maj; 1019 | 1020 | h = g; 1021 | g = f; 1022 | f = e; 1023 | e = (d + t1) | 0; 1024 | d = c; 1025 | c = b; 1026 | b = a; 1027 | a = (t1 + t2) | 0; 1028 | } 1029 | 1030 | // Intermediate hash value 1031 | H[0] = (H[0] + a) | 0; 1032 | H[1] = (H[1] + b) | 0; 1033 | H[2] = (H[2] + c) | 0; 1034 | H[3] = (H[3] + d) | 0; 1035 | H[4] = (H[4] + e) | 0; 1036 | H[5] = (H[5] + f) | 0; 1037 | H[6] = (H[6] + g) | 0; 1038 | H[7] = (H[7] + h) | 0; 1039 | }, 1040 | 1041 | _doFinalize: function () { 1042 | // Shortcuts 1043 | var data = this._data; 1044 | var dataWords = data.words; 1045 | 1046 | var nBitsTotal = this._nDataBytes * 8; 1047 | var nBitsLeft = data.sigBytes * 8; 1048 | 1049 | // Add padding 1050 | dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); 1051 | dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); 1052 | dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; 1053 | data.sigBytes = dataWords.length * 4; 1054 | 1055 | // Hash final blocks 1056 | this._process(); 1057 | 1058 | // Return final computed hash 1059 | return this._hash; 1060 | }, 1061 | 1062 | clone: function () { 1063 | var clone = Hasher.clone.call(this); 1064 | clone._hash = this._hash.clone(); 1065 | 1066 | return clone; 1067 | } 1068 | }); 1069 | 1070 | /** 1071 | * Shortcut function to the hasher's object interface. 1072 | * 1073 | * @param {WordArray|string} message The message to hash. 1074 | * 1075 | * @return {WordArray} The hash. 1076 | * 1077 | * @static 1078 | * 1079 | * @example 1080 | * 1081 | * var hash = CryptoJS.SHA256('message'); 1082 | * var hash = CryptoJS.SHA256(wordArray); 1083 | */ 1084 | C.SHA256 = Hasher._createHelper(SHA256); 1085 | 1086 | /** 1087 | * Shortcut function to the HMAC's object interface. 1088 | * 1089 | * @param {WordArray|string} message The message to hash. 1090 | * @param {WordArray|string} key The secret key. 1091 | * 1092 | * @return {WordArray} The HMAC. 1093 | * 1094 | * @static 1095 | * 1096 | * @example 1097 | * 1098 | * var hmac = CryptoJS.HmacSHA256(message, key); 1099 | */ 1100 | C.HmacSHA256 = Hasher._createHmacHelper(SHA256); 1101 | }(Math)); 1102 | 1103 | 1104 | return CryptoJS.SHA256; 1105 | 1106 | })); 1107 | },{"./core":1}],5:[function(require,module,exports){ 1108 | // shim for using process in browser 1109 | 1110 | var process = module.exports = {}; 1111 | var queue = []; 1112 | var draining = false; 1113 | var currentQueue; 1114 | var queueIndex = -1; 1115 | 1116 | function cleanUpNextTick() { 1117 | draining = false; 1118 | if (currentQueue.length) { 1119 | queue = currentQueue.concat(queue); 1120 | } else { 1121 | queueIndex = -1; 1122 | } 1123 | if (queue.length) { 1124 | drainQueue(); 1125 | } 1126 | } 1127 | 1128 | function drainQueue() { 1129 | if (draining) { 1130 | return; 1131 | } 1132 | var timeout = setTimeout(cleanUpNextTick); 1133 | draining = true; 1134 | 1135 | var len = queue.length; 1136 | while(len) { 1137 | currentQueue = queue; 1138 | queue = []; 1139 | while (++queueIndex < len) { 1140 | if (currentQueue) { 1141 | currentQueue[queueIndex].run(); 1142 | } 1143 | } 1144 | queueIndex = -1; 1145 | len = queue.length; 1146 | } 1147 | currentQueue = null; 1148 | draining = false; 1149 | clearTimeout(timeout); 1150 | } 1151 | 1152 | process.nextTick = function (fun) { 1153 | var args = new Array(arguments.length - 1); 1154 | if (arguments.length > 1) { 1155 | for (var i = 1; i < arguments.length; i++) { 1156 | args[i - 1] = arguments[i]; 1157 | } 1158 | } 1159 | queue.push(new Item(fun, args)); 1160 | if (queue.length === 1 && !draining) { 1161 | setTimeout(drainQueue, 0); 1162 | } 1163 | }; 1164 | 1165 | // v8 likes predictible objects 1166 | function Item(fun, array) { 1167 | this.fun = fun; 1168 | this.array = array; 1169 | } 1170 | Item.prototype.run = function () { 1171 | this.fun.apply(null, this.array); 1172 | }; 1173 | process.title = 'browser'; 1174 | process.browser = true; 1175 | process.env = {}; 1176 | process.argv = []; 1177 | process.version = ''; // empty string to avoid regexp issues 1178 | process.versions = {}; 1179 | 1180 | function noop() {} 1181 | 1182 | process.on = noop; 1183 | process.addListener = noop; 1184 | process.once = noop; 1185 | process.off = noop; 1186 | process.removeListener = noop; 1187 | process.removeAllListeners = noop; 1188 | process.emit = noop; 1189 | 1190 | process.binding = function (name) { 1191 | throw new Error('process.binding is not supported'); 1192 | }; 1193 | 1194 | process.cwd = function () { return '/' }; 1195 | process.chdir = function (dir) { 1196 | throw new Error('process.chdir is not supported'); 1197 | }; 1198 | process.umask = function() { return 0; }; 1199 | 1200 | },{}],6:[function(require,module,exports){ 1201 | 'use strict'; 1202 | var strictUriEncode = require('strict-uri-encode'); 1203 | 1204 | function encode(value, strict) { 1205 | return strict ? strictUriEncode(value) : encodeURIComponent(value); 1206 | } 1207 | 1208 | exports.extract = function (str) { 1209 | return str.split('?')[1] || ''; 1210 | }; 1211 | 1212 | exports.parse = function (str) { 1213 | // Create an object with no prototype 1214 | // https://github.com/sindresorhus/query-string/issues/47 1215 | var ret = Object.create(null); 1216 | 1217 | if (typeof str !== 'string') { 1218 | return ret; 1219 | } 1220 | 1221 | str = str.trim().replace(/^(\?|#|&)/, ''); 1222 | 1223 | if (!str) { 1224 | return ret; 1225 | } 1226 | 1227 | str.split('&').forEach(function (param) { 1228 | var parts = param.replace(/\+/g, ' ').split('='); 1229 | // Firefox (pre 40) decodes `%3D` to `=` 1230 | // https://github.com/sindresorhus/query-string/pull/37 1231 | var key = parts.shift(); 1232 | var val = parts.length > 0 ? parts.join('=') : undefined; 1233 | 1234 | key = decodeURIComponent(key); 1235 | 1236 | // missing `=` should be `null`: 1237 | // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters 1238 | val = val === undefined ? null : decodeURIComponent(val); 1239 | 1240 | if (ret[key] === undefined) { 1241 | ret[key] = val; 1242 | } else if (Array.isArray(ret[key])) { 1243 | ret[key].push(val); 1244 | } else { 1245 | ret[key] = [ret[key], val]; 1246 | } 1247 | }); 1248 | 1249 | return ret; 1250 | }; 1251 | 1252 | exports.stringify = function (obj, opts) { 1253 | opts = opts || {}; 1254 | 1255 | var strict = opts.strict !== false; 1256 | 1257 | return obj ? Object.keys(obj).sort().map(function (key) { 1258 | var val = obj[key]; 1259 | 1260 | if (val === undefined) { 1261 | return ''; 1262 | } 1263 | 1264 | if (val === null) { 1265 | return key; 1266 | } 1267 | 1268 | if (Array.isArray(val)) { 1269 | var result = []; 1270 | 1271 | val.slice().sort().forEach(function (val2) { 1272 | if (val2 === undefined) { 1273 | return; 1274 | } 1275 | 1276 | if (val2 === null) { 1277 | result.push(encode(key, strict)); 1278 | } else { 1279 | result.push(encode(key, strict) + '=' + encode(val2, strict)); 1280 | } 1281 | }); 1282 | 1283 | return result.join('&'); 1284 | } 1285 | 1286 | return encode(key, strict) + '=' + encode(val, strict); 1287 | }).filter(function (x) { 1288 | return x.length > 0; 1289 | }).join('&') : ''; 1290 | }; 1291 | 1292 | },{"strict-uri-encode":7}],7:[function(require,module,exports){ 1293 | 'use strict'; 1294 | module.exports = function (str) { 1295 | return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { 1296 | return '%' + c.charCodeAt(0).toString(16).toUpperCase(); 1297 | }); 1298 | }; 1299 | 1300 | },{}],8:[function(require,module,exports){ 1301 | 'use strict'; 1302 | 1303 | var _interceptor = require('./services/interceptor'); 1304 | 1305 | var _interceptor2 = _interopRequireDefault(_interceptor); 1306 | 1307 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1308 | 1309 | angular.module('angular-aws-apig', []).provider('APIGInterceptor', _interceptor2.default); 1310 | 1311 | },{"./services/interceptor":14}],9:[function(require,module,exports){ 1312 | (function (process){ 1313 | 'use strict'; 1314 | 1315 | var aws4 = exports, 1316 | querystring = require('query-string'), 1317 | hmac = require('./hmac'), 1318 | hash = require('./hash'), 1319 | byteLength = require('./byte-length'); 1320 | 1321 | // http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html 1322 | 1323 | // This function assumes the string has already been percent encoded 1324 | function encodeRfc3986(urlEncodedString) { 1325 | return urlEncodedString.replace(/[!'()*]/g, function (c) { 1326 | return '%' + c.charCodeAt(0).toString(16).toUpperCase(); 1327 | }); 1328 | } 1329 | 1330 | // request: { path | body, [host], [method], [headers], [service], [region] } 1331 | // credentials: { accessKeyId, secretAccessKey, [sessionToken] } 1332 | function RequestSigner(request, credentials) { 1333 | 1334 | var headers = request.headers = request.headers || {}, 1335 | hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host); 1336 | 1337 | this.request = request; 1338 | this.credentials = credentials || this.defaultCredentials(); 1339 | 1340 | this.service = request.service || hostParts[0] || ''; 1341 | this.region = request.region || hostParts[1] || 'us-east-1'; 1342 | 1343 | // SES uses a different domain from the service name 1344 | if (this.service === 'email') this.service = 'ses'; 1345 | 1346 | if (!request.method && request.body) request.method = 'POST'; 1347 | 1348 | if (!headers.Host && !headers.host) { 1349 | headers.Host = request.hostname || request.host || this.createHost(); 1350 | 1351 | // If a port is specified explicitly, use it as is 1352 | if (request.port) headers.Host += ':' + request.port; 1353 | } 1354 | if (!request.hostname && !request.host) request.hostname = headers.Host || headers.host; 1355 | } 1356 | 1357 | RequestSigner.prototype.matchHost = function (host) { 1358 | var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com$/); 1359 | var hostParts = (match || []).slice(1, 3); 1360 | 1361 | // ES's hostParts are sometimes the other way round, if the value that is expected 1362 | // to be region equals ‘es’ switch them back 1363 | // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com 1364 | if (hostParts[1] === 'es') hostParts = hostParts.reverse(); 1365 | 1366 | return hostParts; 1367 | }; 1368 | 1369 | // http://docs.aws.amazon.com/general/latest/gr/rande.html 1370 | RequestSigner.prototype.isSingleRegion = function () { 1371 | // Special case for S3 and SimpleDB in us-east-1 1372 | if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true; 1373 | 1374 | return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'].indexOf(this.service) >= 0; 1375 | }; 1376 | 1377 | RequestSigner.prototype.createHost = function () { 1378 | var region = this.isSingleRegion() ? '' : (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region, 1379 | service = this.service === 'ses' ? 'email' : this.service; 1380 | return service + region + '.amazonaws.com'; 1381 | }; 1382 | 1383 | RequestSigner.prototype.prepareRequest = function () { 1384 | this.parsePath(); 1385 | 1386 | var request = this.request, 1387 | headers = request.headers, 1388 | query; 1389 | 1390 | if (request.signQuery) { 1391 | 1392 | this.parsedPath.query = query = this.parsedPath.query || {}; 1393 | 1394 | if (this.credentials.sessionToken) query['X-Amz-Security-Token'] = this.credentials.sessionToken; 1395 | 1396 | if (this.service === 's3' && !query['X-Amz-Expires']) query['X-Amz-Expires'] = 86400; 1397 | 1398 | if (query['X-Amz-Date']) this.datetime = query['X-Amz-Date'];else query['X-Amz-Date'] = this.getDateTime(); 1399 | 1400 | query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'; 1401 | query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString(); 1402 | query['X-Amz-SignedHeaders'] = this.signedHeaders(); 1403 | } else { 1404 | 1405 | if (!request.doNotModifyHeaders) { 1406 | if (request.body && !headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'; 1407 | 1408 | if (request.body && !headers['Content-Length'] && !headers['content-length']) headers['Content-Length'] = byteLength(request.body); 1409 | 1410 | if (this.credentials.sessionToken) headers['X-Amz-Security-Token'] = this.credentials.sessionToken; 1411 | 1412 | if (this.service === 's3') headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex'); 1413 | 1414 | if (headers['X-Amz-Date']) this.datetime = headers['X-Amz-Date'];else headers['X-Amz-Date'] = this.getDateTime(); 1415 | } 1416 | 1417 | delete headers.Authorization; 1418 | delete headers.authorization; 1419 | } 1420 | }; 1421 | 1422 | RequestSigner.prototype.sign = function () { 1423 | if (!this.parsedPath) this.prepareRequest(); 1424 | 1425 | if (this.request.signQuery) { 1426 | this.parsedPath.query['X-Amz-Signature'] = this.signature(); 1427 | } else { 1428 | this.request.headers.Authorization = this.authHeader(); 1429 | } 1430 | 1431 | this.request.path = this.formatPath(); 1432 | 1433 | return this.request; 1434 | }; 1435 | 1436 | RequestSigner.prototype.getDateTime = function () { 1437 | if (!this.datetime) { 1438 | var headers = this.request.headers, 1439 | date = new Date(headers.Date || headers.date || new Date()); 1440 | 1441 | this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, ''); 1442 | } 1443 | return this.datetime; 1444 | }; 1445 | 1446 | RequestSigner.prototype.getDate = function () { 1447 | return this.getDateTime().substr(0, 8); 1448 | }; 1449 | 1450 | RequestSigner.prototype.authHeader = function () { 1451 | return ['AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), 'SignedHeaders=' + this.signedHeaders(), 'Signature=' + this.signature()].join(', '); 1452 | }; 1453 | 1454 | RequestSigner.prototype.signature = function () { 1455 | var date = this.getDate(); 1456 | var kDate = hmac('AWS4' + this.credentials.secretAccessKey, date); 1457 | var kRegion = hmac(kDate, this.region); 1458 | var kService = hmac(kRegion, this.service); 1459 | var kCredentials = hmac(kService, 'aws4_request'); 1460 | return hmac(kCredentials, this.stringToSign(), 'hex'); 1461 | }; 1462 | 1463 | RequestSigner.prototype.stringToSign = function () { 1464 | return ['AWS4-HMAC-SHA256', this.getDateTime(), this.credentialString(), hash(this.canonicalString(), 'hex')].join('\n'); 1465 | }; 1466 | 1467 | RequestSigner.prototype.canonicalString = function () { 1468 | if (!this.parsedPath) this.prepareRequest(); 1469 | 1470 | var pathStr = this.parsedPath.path, 1471 | query = this.parsedPath.query, 1472 | queryStr = '', 1473 | normalizePath = this.service !== 's3', 1474 | decodePath = this.service === 's3' || this.request.doNotEncodePath, 1475 | decodeSlashesInPath = this.service === 's3', 1476 | firstValOnly = this.service === 's3', 1477 | bodyHash = this.service === 's3' && this.request.signQuery ? 'UNSIGNED-PAYLOAD' : hash(this.request.body || '', 'hex'); 1478 | 1479 | if (query) { 1480 | queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function (obj, key) { 1481 | if (!key) return obj; 1482 | obj[key] = !Array.isArray(query[key]) ? query[key] : firstValOnly ? query[key][0] : query[key].slice().sort(); 1483 | return obj; 1484 | }, {}))); 1485 | } 1486 | if (pathStr !== '/') { 1487 | if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/'); 1488 | pathStr = pathStr.split('/').reduce(function (path, piece) { 1489 | if (normalizePath && piece === '..') { 1490 | path.pop(); 1491 | } else if (!normalizePath || piece !== '.') { 1492 | if (decodePath) piece = decodeURIComponent(piece); 1493 | path.push(encodeRfc3986(encodeURIComponent(piece))); 1494 | } 1495 | return path; 1496 | }, []).join('/'); 1497 | if (pathStr[0] !== '/') pathStr = '/' + pathStr; 1498 | if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/'); 1499 | } 1500 | 1501 | return [this.request.method || 'GET', pathStr, queryStr, this.canonicalHeaders() + '\n', this.signedHeaders(), bodyHash].join('\n'); 1502 | }; 1503 | 1504 | RequestSigner.prototype.canonicalHeaders = function () { 1505 | var headers = this.request.headers; 1506 | function trimAll(header) { 1507 | return header.toString().trim().replace(/\s+/g, ' '); 1508 | } 1509 | return Object.keys(headers).sort(function (a, b) { 1510 | return a.toLowerCase() < b.toLowerCase() ? -1 : 1; 1511 | }).map(function (key) { 1512 | return key.toLowerCase() + ':' + trimAll(headers[key]); 1513 | }).join('\n'); 1514 | }; 1515 | 1516 | RequestSigner.prototype.signedHeaders = function () { 1517 | return Object.keys(this.request.headers).map(function (key) { 1518 | return key.toLowerCase(); 1519 | }).sort().join(';'); 1520 | }; 1521 | 1522 | RequestSigner.prototype.credentialString = function () { 1523 | return [this.getDate(), this.region, this.service, 'aws4_request'].join('/'); 1524 | }; 1525 | 1526 | RequestSigner.prototype.defaultCredentials = function () { 1527 | var env = process.env; 1528 | return { 1529 | accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, 1530 | secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, 1531 | sessionToken: env.AWS_SESSION_TOKEN 1532 | }; 1533 | }; 1534 | 1535 | RequestSigner.prototype.parsePath = function () { 1536 | var path = this.request.path || '/', 1537 | queryIx = path.indexOf('?'), 1538 | query = null; 1539 | 1540 | if (queryIx >= 0) { 1541 | query = querystring.parse(path.slice(queryIx + 1)); 1542 | path = path.slice(0, queryIx); 1543 | } 1544 | 1545 | // S3 doesn't always encode characters > 127 correctly and 1546 | // all services don't encode characters > 255 correctly 1547 | // So if there are non-reserved chars (and it's not already all % encoded), just encode them all 1548 | if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) { 1549 | path = path.split('/').map(function (piece) { 1550 | return encodeURIComponent(decodeURIComponent(piece)); 1551 | }).join('/'); 1552 | } 1553 | 1554 | this.parsedPath = { 1555 | path: path, 1556 | query: query 1557 | }; 1558 | }; 1559 | 1560 | RequestSigner.prototype.formatPath = function () { 1561 | var path = this.parsedPath.path, 1562 | query = this.parsedPath.query; 1563 | 1564 | if (!query) return path; 1565 | 1566 | // Services don't support empty query string keys 1567 | if (query[''] != null) delete query['']; 1568 | 1569 | return path + '?' + encodeRfc3986(querystring.stringify(query)); 1570 | }; 1571 | 1572 | aws4.RequestSigner = RequestSigner; 1573 | 1574 | aws4.sign = function (request, credentials) { 1575 | return new RequestSigner(request, credentials).sign(); 1576 | }; 1577 | 1578 | }).call(this,require('_process')) 1579 | },{"./byte-length":10,"./hash":11,"./hmac":13,"_process":5,"query-string":6}],10:[function(require,module,exports){ 1580 | "use strict"; 1581 | 1582 | module.exports = function byteLength(str) { 1583 | // returns the byte length of an utf8 string 1584 | var s = str.length; 1585 | for (var i = str.length - 1; i >= 0; i--) { 1586 | var code = str.charCodeAt(i); 1587 | if (code > 0x7f && code <= 0x7ff) { 1588 | s += 1; 1589 | } else if (code > 0x7ff && code <= 0xffff) { 1590 | s += 2; 1591 | } 1592 | if (code >= 0xDC00 && code <= 0xDFFF) { 1593 | i--; // trail surrogate 1594 | } 1595 | } 1596 | return s; 1597 | }; 1598 | 1599 | },{}],11:[function(require,module,exports){ 1600 | 'use strict'; 1601 | 1602 | var sha256 = require('crypto-js/sha256'); 1603 | var hexer = require('./hexer'); 1604 | 1605 | module.exports = function hash(string) { 1606 | var hash = sha256(string); 1607 | var output = hash.toString(hexer); 1608 | return output; 1609 | }; 1610 | 1611 | },{"./hexer":12,"crypto-js/sha256":4}],12:[function(require,module,exports){ 1612 | 'use strict'; 1613 | 1614 | module.exports = { 1615 | stringify: hexStringify 1616 | }; 1617 | 1618 | function hexStringify(wordArray) { 1619 | // Shortcuts 1620 | var words = wordArray.words; 1621 | var sigBytes = wordArray.sigBytes; 1622 | 1623 | // Convert 1624 | var hexChars = []; 1625 | for (var i = 0; i < sigBytes; i++) { 1626 | var bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 0xff; 1627 | hexChars.push((bite >>> 4).toString(16)); 1628 | hexChars.push((bite & 0x0f).toString(16)); 1629 | } 1630 | return hexChars.join(''); 1631 | } 1632 | 1633 | },{}],13:[function(require,module,exports){ 1634 | 'use strict'; 1635 | 1636 | // var createHmac = require('./vendor/create-hmac') 1637 | // var CryptoJS = require('crypto-js') 1638 | var hmacSHA256 = require('crypto-js/hmac-sha256'); 1639 | var hexer = require('./hexer'); 1640 | 1641 | module.exports = function hmac(key, string, encoding) { 1642 | encoding = encoding; 1643 | var hash = hmacSHA256(string, key); 1644 | var output = hash; 1645 | if (encoding === 'HEX') { 1646 | output = output.toString(hexer); 1647 | } 1648 | return output; 1649 | }; 1650 | 1651 | },{"./hexer":12,"crypto-js/hmac-sha256":2}],14:[function(require,module,exports){ 1652 | 'use strict'; 1653 | 1654 | Object.defineProperty(exports, "__esModule", { 1655 | value: true 1656 | }); 1657 | 1658 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 1659 | 1660 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 1661 | 1662 | var _aws = require('../lib/aws4'); 1663 | 1664 | var _aws2 = _interopRequireDefault(_aws); 1665 | 1666 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1667 | 1668 | function APIGInterceptorProvider() { 1669 | var _this = this; 1670 | 1671 | this.headers = { 1672 | 'Content-Type': 'application/json;charset=UTF-8' 1673 | }; 1674 | this.region = 'us-east-1'; 1675 | this.service = 'execute-api'; 1676 | this.urlRegex = ''; 1677 | 1678 | this.headersGetter = /*@ngInject*/["request", function (request) { 1679 | return request.headers; 1680 | }]; 1681 | 1682 | this.credentialsGetter = function () { 1683 | try { 1684 | return AWS.config.credentials; 1685 | } catch (err) { 1686 | throw new Error(err + ', please specify credentialsGetter function'); 1687 | } 1688 | }; 1689 | 1690 | this.config = function (options) { 1691 | _extends(_this, options); 1692 | }; 1693 | 1694 | this.parseUrl = function (url) { 1695 | var parser = document.createElement('a'); 1696 | parser.href = url; 1697 | return { 1698 | host: parser.host.split(':')[0], 1699 | path: parser.pathname 1700 | }; 1701 | }; 1702 | 1703 | this.transformData = function (config) { 1704 | var data = config.data; 1705 | if (Array.isArray(config.transformRequest)) { 1706 | config.transformRequest.forEach(function (transformer) { 1707 | data = transformer(data); 1708 | }); 1709 | } else { 1710 | data = config.transformRequest(data); 1711 | } 1712 | return data; 1713 | }; 1714 | 1715 | this.$get = /*@ngInject*/["$q", "$injector", "$rootScope", function ($q, $injector, $rootScope) { 1716 | var config = _this; 1717 | return { 1718 | request: function request(_request) { 1719 | var _this2 = this; 1720 | 1721 | var urlRegex = new RegExp(config.urlRegex); 1722 | if (urlRegex.test(_request.url)) { 1723 | var _ret = function () { 1724 | _extends(_request.headers, config.headers); 1725 | var parser = config.parseUrl(_request.url); 1726 | var headers = $injector.invoke(config.headersGetter, _this2, { request: _request }); 1727 | var params = _request.params ? '?' + _request.paramSerializer(_request.params) : ''; 1728 | var data = config.transformData(_request); 1729 | var credsPromise = $q.when($injector.invoke(config.credentialsGetter, _this2, { request: _request })); 1730 | if (!data) delete headers['Content-Type']; 1731 | return { 1732 | v: credsPromise.then(function (creds) { 1733 | var options = _aws2.default.sign({ 1734 | service: config.service, 1735 | region: config.region, 1736 | host: parser.host, 1737 | path: parser.path + params, 1738 | method: _request.method, 1739 | body: data, 1740 | headers: headers 1741 | }, creds); 1742 | 1743 | delete options.headers['Host']; 1744 | delete options.headers['Content-Length']; 1745 | 1746 | _request.headers = options.headers; 1747 | _request.data = options.body; 1748 | _request.transformRequest = []; 1749 | return _request; 1750 | }) 1751 | }; 1752 | }(); 1753 | 1754 | if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; 1755 | } else { 1756 | return _request; 1757 | } 1758 | }, 1759 | responseError: function responseError(rejection) { 1760 | $rootScope.$broadcast('$APIGError', rejection.data); 1761 | return $q.reject(rejection); 1762 | } 1763 | }; 1764 | }]; 1765 | } 1766 | 1767 | exports.default = APIGInterceptorProvider; 1768 | 1769 | },{"../lib/aws4":9}]},{},[8]); 1770 | -------------------------------------------------------------------------------- /dist/angular-aws-apig.min.js: -------------------------------------------------------------------------------- 1 | !function t(e,r,n){function i(o,a){if(!r[o]){if(!e[o]){var c="function"==typeof require&&require;if(!a&&c)return c(o,!0);if(s)return s(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var h=r[o]={exports:{}};e[o][0].call(h.exports,function(t){var r=e[o][1][t];return i(r?r:t)},h,h.exports,t,e,r,n)}return r[o].exports}for(var s="function"==typeof require&&require,o=0;os;s++){var o=r[s>>>2]>>>24-s%4*8&255;e[n+s>>>2]|=o<<24-(n+s)%4*8}else for(var s=0;i>s;s+=4)e[n+s>>>2]=r[s>>>2];return this.sigBytes+=i,this},clamp:function(){var e=this.words,r=this.sigBytes;e[r>>>2]&=4294967295<<32-r%4*8,e.length=t.ceil(r/4)},clone:function(){var t=i.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var r,n=[],i=function(e){var e=e,r=987654321,n=4294967295;return function(){r=36969*(65535&r)+(r>>16)&n,e=18e3*(65535&e)+(e>>16)&n;var i=(r<<16)+e&n;return i/=4294967296,i+=.5,i*(t.random()>.5?1:-1)}},o=0;e>o;o+=4){var a=i(4294967296*(r||t.random()));r=987654071*a(),n.push(4294967296*a()|0)}return new s.init(n,e)}}),o=r.enc={},a=o.Hex={stringify:function(t){for(var e=t.words,r=t.sigBytes,n=[],i=0;r>i;i++){var s=e[i>>>2]>>>24-i%4*8&255;n.push((s>>>4).toString(16)),n.push((15&s).toString(16))}return n.join("")},parse:function(t){for(var e=t.length,r=[],n=0;e>n;n+=2)r[n>>>3]|=parseInt(t.substr(n,2),16)<<24-n%8*4;return new s.init(r,e/2)}},c=o.Latin1={stringify:function(t){for(var e=t.words,r=t.sigBytes,n=[],i=0;r>i;i++){var s=e[i>>>2]>>>24-i%4*8&255;n.push(String.fromCharCode(s))}return n.join("")},parse:function(t){for(var e=t.length,r=[],n=0;e>n;n++)r[n>>>2]|=(255&t.charCodeAt(n))<<24-n%4*8;return new s.init(r,e)}},u=o.Utf8={stringify:function(t){try{return decodeURIComponent(escape(c.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return c.parse(unescape(encodeURIComponent(t)))}},h=n.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=u.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var r=this._data,n=r.words,i=r.sigBytes,o=this.blockSize,a=4*o,c=i/a;c=e?t.ceil(c):t.max((0|c)-this._minBufferSize,0);var u=c*o,h=t.min(4*u,i);if(u){for(var f=0;u>f;f+=o)this._doProcessBlock(n,f);var p=n.splice(0,u);r.sigBytes-=h}return new s.init(p,h)},clone:function(){var t=i.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),f=(n.Hasher=h.extend({cfg:i.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){h.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,r){return new t.init(r).finalize(e)}},_createHmacHelper:function(t){return function(e,r){return new f.HMAC.init(t,r).finalize(e)}}}),r.algo={});return r}(Math);return t})},{}],2:[function(t,e,r){!function(n,i,s){"object"==typeof r?e.exports=r=i(t("./core"),t("./sha256"),t("./hmac")):"function"==typeof define&&define.amd?define(["./core","./sha256","./hmac"],i):i(n.CryptoJS)}(this,function(t){return t.HmacSHA256})},{"./core":1,"./hmac":3,"./sha256":4}],3:[function(t,e,r){!function(n,i){"object"==typeof r?e.exports=r=i(t("./core")):"function"==typeof define&&define.amd?define(["./core"],i):i(n.CryptoJS)}(this,function(t){!function(){var e=t,r=e.lib,n=r.Base,i=e.enc,s=i.Utf8,o=e.algo;o.HMAC=n.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=s.parse(e));var r=t.blockSize,n=4*r;e.sigBytes>n&&(e=t.finalize(e)),e.clamp();for(var i=this._oKey=e.clone(),o=this._iKey=e.clone(),a=i.words,c=o.words,u=0;r>u;u++)a[u]^=1549556828,c[u]^=909522486;i.sigBytes=o.sigBytes=n,this.reset()},reset:function(){var t=this._hasher;t.reset(),t.update(this._iKey)},update:function(t){return this._hasher.update(t),this},finalize:function(t){var e=this._hasher,r=e.finalize(t);e.reset();var n=e.finalize(this._oKey.clone().concat(r));return n}})}()})},{"./core":1}],4:[function(t,e,r){!function(n,i){"object"==typeof r?e.exports=r=i(t("./core")):"function"==typeof define&&define.amd?define(["./core"],i):i(n.CryptoJS)}(this,function(t){return function(e){var r=t,n=r.lib,i=n.WordArray,s=n.Hasher,o=r.algo,a=[],c=[];!function(){function t(t){for(var r=e.sqrt(t),n=2;r>=n;n++)if(!(t%n))return!1;return!0}function r(t){return 4294967296*(t-(0|t))|0}for(var n=2,i=0;64>i;)t(n)&&(8>i&&(a[i]=r(e.pow(n,.5))),c[i]=r(e.pow(n,1/3)),i++),n++}();var u=[],h=o.SHA256=s.extend({_doReset:function(){this._hash=new i.init(a.slice(0))},_doProcessBlock:function(t,e){for(var r=this._hash.words,n=r[0],i=r[1],s=r[2],o=r[3],a=r[4],h=r[5],f=r[6],p=r[7],d=0;64>d;d++){if(16>d)u[d]=0|t[e+d];else{var l=u[d-15],g=(l<<25|l>>>7)^(l<<14|l>>>18)^l>>>3,y=u[d-2],v=(y<<15|y>>>17)^(y<<13|y>>>19)^y>>>10;u[d]=g+u[d-7]+v+u[d-16]}var m=a&h^~a&f,S=n&i^n&s^i&s,A=(n<<30|n>>>2)^(n<<19|n>>>13)^(n<<10|n>>>22),_=(a<<26|a>>>6)^(a<<21|a>>>11)^(a<<7|a>>>25),w=p+_+m+c[d]+u[d],C=A+S;p=f,f=h,h=a,a=o+w|0,o=s,s=i,i=n,n=w+C|0}r[0]=r[0]+n|0,r[1]=r[1]+i|0,r[2]=r[2]+s|0,r[3]=r[3]+o|0,r[4]=r[4]+a|0,r[5]=r[5]+h|0,r[6]=r[6]+f|0,r[7]=r[7]+p|0},_doFinalize:function(){var t=this._data,r=t.words,n=8*this._nDataBytes,i=8*t.sigBytes;return r[i>>>5]|=128<<24-i%32,r[(i+64>>>9<<4)+14]=e.floor(n/4294967296),r[(i+64>>>9<<4)+15]=n,t.sigBytes=4*r.length,this._process(),this._hash},clone:function(){var t=s.clone.call(this);return t._hash=this._hash.clone(),t}});r.SHA256=s._createHelper(h),r.HmacSHA256=s._createHmacHelper(h)}(Math),t.SHA256})},{"./core":1}],5:[function(t,e,r){function n(){h=!1,a.length?u=a.concat(u):f=-1,u.length&&i()}function i(){if(!h){var t=setTimeout(n);h=!0;for(var e=u.length;e;){for(a=u,u=[];++f1)for(var r=1;r=0&&"us-east-1"===this.region?!0:["cloudfront","ls","route53","iam","importexport","sts"].indexOf(this.service)>=0},i.prototype.createHost=function(){var t=this.isSingleRegion()?"":("s3"===this.service&&"us-east-1"!==this.region?"-":".")+this.region,e="ses"===this.service?"email":this.service;return e+t+".amazonaws.com"},i.prototype.prepareRequest=function(){this.parsePath();var t,e=this.request,r=e.headers;e.signQuery?(this.parsedPath.query=t=this.parsedPath.query||{},this.credentials.sessionToken&&(t["X-Amz-Security-Token"]=this.credentials.sessionToken),"s3"!==this.service||t["X-Amz-Expires"]||(t["X-Amz-Expires"]=86400),t["X-Amz-Date"]?this.datetime=t["X-Amz-Date"]:t["X-Amz-Date"]=this.getDateTime(),t["X-Amz-Algorithm"]="AWS4-HMAC-SHA256",t["X-Amz-Credential"]=this.credentials.accessKeyId+"/"+this.credentialString(),t["X-Amz-SignedHeaders"]=this.signedHeaders()):(e.doNotModifyHeaders||(!e.body||r["Content-Type"]||r["content-type"]||(r["Content-Type"]="application/x-www-form-urlencoded; charset=utf-8"),!e.body||r["Content-Length"]||r["content-length"]||(r["Content-Length"]=u(e.body)),this.credentials.sessionToken&&(r["X-Amz-Security-Token"]=this.credentials.sessionToken),"s3"===this.service&&(r["X-Amz-Content-Sha256"]=c(this.request.body||"","hex")),r["X-Amz-Date"]?this.datetime=r["X-Amz-Date"]:r["X-Amz-Date"]=this.getDateTime()),delete r.Authorization,delete r.authorization)},i.prototype.sign=function(){return this.parsedPath||this.prepareRequest(),this.request.signQuery?this.parsedPath.query["X-Amz-Signature"]=this.signature():this.request.headers.Authorization=this.authHeader(),this.request.path=this.formatPath(),this.request},i.prototype.getDateTime=function(){if(!this.datetime){var t=this.request.headers,e=new Date(t.Date||t.date||new Date);this.datetime=e.toISOString().replace(/[:\-]|\.\d{3}/g,"")}return this.datetime},i.prototype.getDate=function(){return this.getDateTime().substr(0,8)},i.prototype.authHeader=function(){return["AWS4-HMAC-SHA256 Credential="+this.credentials.accessKeyId+"/"+this.credentialString(),"SignedHeaders="+this.signedHeaders(),"Signature="+this.signature()].join(", ")},i.prototype.signature=function(){var t=this.getDate(),e=a("AWS4"+this.credentials.secretAccessKey,t),r=a(e,this.region),n=a(r,this.service),i=a(n,"aws4_request");return a(i,this.stringToSign(),"hex")},i.prototype.stringToSign=function(){return["AWS4-HMAC-SHA256",this.getDateTime(),this.credentialString(),c(this.canonicalString(),"hex")].join("\n")},i.prototype.canonicalString=function(){this.parsedPath||this.prepareRequest();var t=this.parsedPath.path,e=this.parsedPath.query,r="",i="s3"!==this.service,s="s3"===this.service||this.request.doNotEncodePath,a="s3"===this.service,u="s3"===this.service,h="s3"===this.service&&this.request.signQuery?"UNSIGNED-PAYLOAD":c(this.request.body||"","hex");return e&&(r=n(o.stringify(Object.keys(e).sort().reduce(function(t,r){return r?(t[r]=Array.isArray(e[r])?u?e[r][0]:e[r].slice().sort():e[r],t):t},{})))),"/"!==t&&(i&&(t=t.replace(/\/{2,}/g,"/")),t=t.split("/").reduce(function(t,e){return i&&".."===e?t.pop():i&&"."===e||(s&&(e=decodeURIComponent(e)),t.push(n(encodeURIComponent(e)))),t},[]).join("/"),"/"!==t[0]&&(t="/"+t),a&&(t=t.replace(/%2F/g,"/"))),[this.request.method||"GET",t,r,this.canonicalHeaders()+"\n",this.signedHeaders(),h].join("\n")},i.prototype.canonicalHeaders=function(){function t(t){return t.toString().trim().replace(/\s+/g," ")}var e=this.request.headers;return Object.keys(e).sort(function(t,e){return t.toLowerCase()=0&&(r=o.parse(t.slice(e+1)),t=t.slice(0,e)),/[^0-9A-Za-z!'()*\-._~%\/]/.test(t)&&(t=t.split("/").map(function(t){return encodeURIComponent(decodeURIComponent(t))}).join("/")),this.parsedPath={path:t,query:r}},i.prototype.formatPath=function(){var t=this.parsedPath.path,e=this.parsedPath.query;return e?(null!=e[""]&&delete e[""],t+"?"+n(o.stringify(e))):t},s.RequestSigner=i,s.sign=function(t,e){return new i(t,e).sign()}}).call(this,t("_process"))},{"./byte-length":10,"./hash":11,"./hmac":13,_process:5,"query-string":6}],10:[function(t,e,r){"use strict";e.exports=function(t){for(var e=t.length,r=t.length-1;r>=0;r--){var n=t.charCodeAt(r);n>127&&2047>=n?e+=1:n>2047&&65535>=n&&(e+=2),n>=56320&&57343>=n&&r--}return e}},{}],11:[function(t,e,r){"use strict";var n=t("crypto-js/sha256"),i=t("./hexer");e.exports=function s(t){var s=n(t),e=s.toString(i);return e}},{"./hexer":12,"crypto-js/sha256":4}],12:[function(t,e,r){"use strict";function n(t){for(var e=t.words,r=t.sigBytes,n=[],i=0;r>i;i++){var s=e[i>>>2]>>>24-i%4*8&255;n.push((s>>>4).toString(16)),n.push((15&s).toString(16))}return n.join("")}e.exports={stringify:n}},{}],13:[function(t,e,r){"use strict";var n=t("crypto-js/hmac-sha256"),i=t("./hexer");e.exports=function(t,e,r){r=r;var s=n(e,t),o=s;return"HEX"===r&&(o=o.toString(i)),o}},{"./hexer":12,"crypto-js/hmac-sha256":2}],14:[function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function i(){var t=this;this.headers={"Content-Type":"application/json;charset=UTF-8"},this.region="us-east-1",this.service="execute-api",this.urlRegex="",this.headersGetter=["request",function(t){return t.headers}],this.credentialsGetter=function(){try{return AWS.config.credentials}catch(t){throw new Error(t+", please specify credentialsGetter function")}},this.config=function(e){o(t,e)},this.parseUrl=function(t){var e=document.createElement("a");return e.href=t,{host:e.host.split(":")[0],path:e.pathname}},this.transformData=function(t){var e=t.data;return Array.isArray(t.transformRequest)?t.transformRequest.forEach(function(t){e=t(e)}):e=t.transformRequest(e),e},this.$get=["$q","$injector","$rootScope",function(e,r,n){var i=t;return{request:function(t){var n=this,a=new RegExp(i.urlRegex);if(!a.test(t.url))return t;var u=function(){o(t.headers,i.headers);var s=i.parseUrl(t.url),a=r.invoke(i.headersGetter,n,{request:t}),u=t.params?"?"+t.paramSerializer(t.params):"",h=i.transformData(t),f=e.when(r.invoke(i.credentialsGetter,n,{request:t}));return h||delete a["Content-Type"],{v:f.then(function(e){var r=c["default"].sign({service:i.service,region:i.region,host:s.host,path:s.path+u,method:t.method,body:h,headers:a},e);return delete r.headers.Host,delete r.headers["Content-Length"],t.headers=r.headers,t.data=r.body,t.transformRequest=[],t})}}();return"object"===("undefined"==typeof u?"undefined":s(u))?u.v:void 0},responseError:function(t){return n.$broadcast("$APIGError",t.data),e.reject(t)}}}]}Object.defineProperty(r,"__esModule",{value:!0});var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},o=Object.assign||function(t){for(var e=1;e= 0 && this.region === 'us-east-1') return true; 63 | 64 | return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'] 65 | .indexOf(this.service) >= 0 66 | }; 67 | 68 | RequestSigner.prototype.createHost = function() { 69 | var region = this.isSingleRegion() ? '' : 70 | (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region, 71 | service = this.service === 'ses' ? 'email' : this.service; 72 | return service + region + '.amazonaws.com' 73 | }; 74 | 75 | RequestSigner.prototype.prepareRequest = function() { 76 | this.parsePath(); 77 | 78 | var request = this.request, headers = request.headers, query; 79 | 80 | if (request.signQuery) { 81 | 82 | this.parsedPath.query = query = this.parsedPath.query || {}; 83 | 84 | if (this.credentials.sessionToken) 85 | query['X-Amz-Security-Token'] = this.credentials.sessionToken; 86 | 87 | if (this.service === 's3' && !query['X-Amz-Expires']) 88 | query['X-Amz-Expires'] = 86400; 89 | 90 | if (query['X-Amz-Date']) 91 | this.datetime = query['X-Amz-Date']; 92 | else 93 | query['X-Amz-Date'] = this.getDateTime(); 94 | 95 | query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'; 96 | query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString(); 97 | query['X-Amz-SignedHeaders'] = this.signedHeaders() 98 | 99 | } else { 100 | 101 | if (!request.doNotModifyHeaders) { 102 | if (request.body && !headers['Content-Type'] && !headers['content-type']) 103 | headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'; 104 | 105 | if (request.body && !headers['Content-Length'] && !headers['content-length']) 106 | headers['Content-Length'] = byteLength(request.body); 107 | 108 | if (this.credentials.sessionToken) 109 | headers['X-Amz-Security-Token'] = this.credentials.sessionToken; 110 | 111 | if (this.service === 's3') 112 | headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex'); 113 | 114 | if (headers['X-Amz-Date']) 115 | this.datetime = headers['X-Amz-Date']; 116 | else 117 | headers['X-Amz-Date'] = this.getDateTime() 118 | } 119 | 120 | delete headers.Authorization; 121 | delete headers.authorization 122 | } 123 | }; 124 | 125 | RequestSigner.prototype.sign = function() { 126 | if (!this.parsedPath) this.prepareRequest(); 127 | 128 | if (this.request.signQuery) { 129 | this.parsedPath.query['X-Amz-Signature'] = this.signature() 130 | } else { 131 | this.request.headers.Authorization = this.authHeader() 132 | } 133 | 134 | this.request.path = this.formatPath(); 135 | 136 | return this.request 137 | }; 138 | 139 | RequestSigner.prototype.getDateTime = function() { 140 | if (!this.datetime) { 141 | var headers = this.request.headers, 142 | date = new Date(headers.Date || headers.date || new Date); 143 | 144 | this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '') 145 | } 146 | return this.datetime 147 | }; 148 | 149 | RequestSigner.prototype.getDate = function() { 150 | return this.getDateTime().substr(0, 8) 151 | }; 152 | 153 | RequestSigner.prototype.authHeader = function() { 154 | return [ 155 | 'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), 156 | 'SignedHeaders=' + this.signedHeaders(), 157 | 'Signature=' + this.signature(), 158 | ].join(', ') 159 | }; 160 | 161 | RequestSigner.prototype.signature = function() { 162 | var date = this.getDate(); 163 | var kDate = hmac('AWS4' + this.credentials.secretAccessKey, date); 164 | var kRegion = hmac(kDate, this.region); 165 | var kService = hmac(kRegion, this.service); 166 | var kCredentials = hmac(kService, 'aws4_request'); 167 | return hmac(kCredentials, this.stringToSign(), 'hex'); 168 | }; 169 | 170 | RequestSigner.prototype.stringToSign = function() { 171 | return [ 172 | 'AWS4-HMAC-SHA256', 173 | this.getDateTime(), 174 | this.credentialString(), 175 | hash(this.canonicalString(), 'hex'), 176 | ].join('\n') 177 | }; 178 | 179 | RequestSigner.prototype.canonicalString = function() { 180 | if (!this.parsedPath) this.prepareRequest(); 181 | 182 | var pathStr = this.parsedPath.path, 183 | query = this.parsedPath.query, 184 | queryStr = '', 185 | normalizePath = this.service !== 's3', 186 | decodePath = this.service === 's3' || this.request.doNotEncodePath, 187 | decodeSlashesInPath = this.service === 's3', 188 | firstValOnly = this.service === 's3', 189 | bodyHash = this.service === 's3' && this.request.signQuery ? 190 | 'UNSIGNED-PAYLOAD' : hash(this.request.body || '', 'hex'); 191 | 192 | if (query) { 193 | queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function(obj, key) { 194 | if (!key) return obj; 195 | obj[key] = !Array.isArray(query[key]) ? query[key] : 196 | (firstValOnly ? query[key][0] : query[key].slice().sort()); 197 | return obj 198 | }, {}))) 199 | } 200 | if (pathStr !== '/') { 201 | if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/'); 202 | pathStr = pathStr.split('/').reduce(function(path, piece) { 203 | if (normalizePath && piece === '..') { 204 | path.pop() 205 | } else if (!normalizePath || piece !== '.') { 206 | if (decodePath) piece = decodeURIComponent(piece); 207 | path.push(encodeRfc3986(encodeURIComponent(piece))) 208 | } 209 | return path 210 | }, []).join('/'); 211 | if (pathStr[0] !== '/') pathStr = '/' + pathStr; 212 | if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/') 213 | } 214 | 215 | return [ 216 | this.request.method || 'GET', 217 | pathStr, 218 | queryStr, 219 | this.canonicalHeaders() + '\n', 220 | this.signedHeaders(), 221 | bodyHash, 222 | ].join('\n') 223 | }; 224 | 225 | RequestSigner.prototype.canonicalHeaders = function() { 226 | var headers = this.request.headers; 227 | function trimAll(header) { 228 | return header.toString().trim().replace(/\s+/g, ' ') 229 | } 230 | return Object.keys(headers) 231 | .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 }) 232 | .map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) }) 233 | .join('\n') 234 | }; 235 | 236 | RequestSigner.prototype.signedHeaders = function() { 237 | return Object.keys(this.request.headers) 238 | .map(function(key) { return key.toLowerCase() }) 239 | .sort() 240 | .join(';') 241 | }; 242 | 243 | RequestSigner.prototype.credentialString = function() { 244 | return [ 245 | this.getDate(), 246 | this.region, 247 | this.service, 248 | 'aws4_request', 249 | ].join('/') 250 | }; 251 | 252 | RequestSigner.prototype.defaultCredentials = function() { 253 | var env = process.env; 254 | return { 255 | accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, 256 | secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, 257 | sessionToken: env.AWS_SESSION_TOKEN, 258 | } 259 | }; 260 | 261 | RequestSigner.prototype.parsePath = function() { 262 | var path = this.request.path || '/', 263 | queryIx = path.indexOf('?'), 264 | query = null; 265 | 266 | if (queryIx >= 0) { 267 | query = querystring.parse(path.slice(queryIx + 1)); 268 | path = path.slice(0, queryIx) 269 | } 270 | 271 | // S3 doesn't always encode characters > 127 correctly and 272 | // all services don't encode characters > 255 correctly 273 | // So if there are non-reserved chars (and it's not already all % encoded), just encode them all 274 | if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) { 275 | path = path.split('/').map(function(piece) { 276 | return encodeURIComponent(decodeURIComponent(piece)) 277 | }).join('/') 278 | } 279 | 280 | this.parsedPath = { 281 | path: path, 282 | query: query, 283 | } 284 | }; 285 | 286 | RequestSigner.prototype.formatPath = function() { 287 | var path = this.parsedPath.path, 288 | query = this.parsedPath.query; 289 | 290 | if (!query) return path; 291 | 292 | // Services don't support empty query string keys 293 | if (query[''] != null) delete query['']; 294 | 295 | return path + '?' + encodeRfc3986(querystring.stringify(query)) 296 | }; 297 | 298 | aws4.RequestSigner = RequestSigner; 299 | 300 | aws4.sign = function(request, credentials) { 301 | return new RequestSigner(request, credentials).sign() 302 | }; -------------------------------------------------------------------------------- /src/lib/byte-length.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function byteLength (str) { 3 | // returns the byte length of an utf8 string 4 | var s = str.length 5 | for (var i = str.length - 1; i >= 0; i--) { 6 | var code = str.charCodeAt(i) 7 | if (code > 0x7f && code <= 0x7ff) { 8 | s += 1 9 | } else if (code > 0x7ff && code <= 0xffff) { 10 | s += 2 11 | } 12 | if (code >= 0xDC00 && code <= 0xDFFF) { 13 | i-- // trail surrogate 14 | } 15 | } 16 | return s 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/hash.js: -------------------------------------------------------------------------------- 1 | var sha256 = require('crypto-js/sha256') 2 | var hexer = require('./hexer') 3 | 4 | module.exports = function hash (string) { 5 | var hash = sha256(string) 6 | var output = hash.toString(hexer) 7 | return output 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/hexer.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stringify: hexStringify 3 | } 4 | 5 | function hexStringify (wordArray) { 6 | // Shortcuts 7 | var words = wordArray.words 8 | var sigBytes = wordArray.sigBytes 9 | 10 | // Convert 11 | var hexChars = [] 12 | for (var i = 0; i < sigBytes; i++) { 13 | var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff 14 | hexChars.push((bite >>> 4).toString(16)) 15 | hexChars.push((bite & 0x0f).toString(16)) 16 | } 17 | return hexChars.join('') 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/hmac.js: -------------------------------------------------------------------------------- 1 | // var createHmac = require('./vendor/create-hmac') 2 | // var CryptoJS = require('crypto-js') 3 | var hmacSHA256 = require('crypto-js/hmac-sha256') 4 | var hexer = require('./hexer') 5 | 6 | module.exports = function hmac (key, string, encoding) { 7 | encoding = encoding 8 | var hash = hmacSHA256(string, key) 9 | var output = hash 10 | if (encoding === 'HEX') { 11 | output = output.toString(hexer) 12 | } 13 | return output 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/services/interceptor.js: -------------------------------------------------------------------------------- 1 | import aws4 from '../lib/aws4'; 2 | 3 | function APIGInterceptorProvider() { 4 | this.headers = { 5 | 'Content-Type': 'application/json;charset=UTF-8' 6 | }; 7 | this.region = 'us-east-1'; 8 | this.service = 'execute-api'; 9 | this.urlRegex = ''; 10 | 11 | this.headersGetter = /*@ngInject*/(request) => { 12 | return request.headers 13 | }; 14 | 15 | this.credentialsGetter = () => { 16 | try { 17 | return AWS.config.credentials; 18 | } catch(err) { 19 | throw new Error(err + ', please specify credentialsGetter function'); 20 | } 21 | }; 22 | 23 | this.config = (options) => { 24 | Object.assign(this, options); 25 | }; 26 | 27 | this.parseUrl = (url) => { 28 | const parser = document.createElement('a'); 29 | parser.href = url; 30 | return { 31 | host: parser.host.split(':')[0], 32 | path: parser.pathname 33 | }; 34 | }; 35 | 36 | this.transformData = (config) => { 37 | let data = config.data; 38 | if (Array.isArray(config.transformRequest)) { 39 | config.transformRequest.forEach((transformer) => { 40 | data = transformer(data); 41 | }); 42 | } else { 43 | data = config.transformRequest(data); 44 | } 45 | return data; 46 | }; 47 | 48 | this.$get = /*@ngInject*/($q, $injector, $rootScope) => { 49 | let config = this; 50 | return { 51 | request(request) { 52 | let urlRegex = new RegExp(config.urlRegex); 53 | if (urlRegex.test(request.url)) { 54 | Object.assign(request.headers, config.headers); 55 | const parser = config.parseUrl(request.url); 56 | const headers = $injector.invoke(config.headersGetter, this, {request}); 57 | const params = request.params ? '?' + request.paramSerializer(request.params) : ''; 58 | const data = config.transformData(request); 59 | const credsPromise = $q.when($injector.invoke(config.credentialsGetter, this, {request})); 60 | if (!data) delete headers['Content-Type']; 61 | return credsPromise.then((creds) => { 62 | const options = aws4.sign({ 63 | service: config.service, 64 | region: config.region, 65 | host: parser.host, 66 | path: parser.path + params, 67 | method: request.method, 68 | body: data, 69 | headers 70 | }, creds); 71 | 72 | delete options.headers['Host']; 73 | delete options.headers['Content-Length']; 74 | 75 | request.headers = options.headers; 76 | request.data = options.body; 77 | request.transformRequest = []; 78 | return request; 79 | }); 80 | } else { 81 | return request; 82 | } 83 | }, 84 | responseError(rejection) { 85 | $rootScope.$broadcast('$APIGError', rejection.data); 86 | return $q.reject(rejection); 87 | } 88 | }; 89 | } 90 | } 91 | 92 | export default APIGInterceptorProvider; -------------------------------------------------------------------------------- /test/angular-aws-apig.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Main Module', () => { 4 | 5 | let module; 6 | 7 | beforeEach(function() { 8 | module = angular.module('angular-aws-apig'); 9 | }); 10 | 11 | it('should load correctly', function() { 12 | expect(module.name).to.equal('angular-aws-apig'); 13 | }); 14 | 15 | }); -------------------------------------------------------------------------------- /test/services/interceptor.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Interceptor', () => { 4 | 5 | let APIGInterceptorProvider; 6 | let APIGInterceptor; 7 | let $httpProvider; 8 | let $httpBackend; 9 | let $http; 10 | let $rootScope; 11 | 12 | const credentials = { 13 | accessKeyId: 'ABCDEF', 14 | secretAccessKey: 'abcdef1234567890', 15 | sessionToken: 'qwertyuiopasdfghjklzxcvbnm1234567890' 16 | }; 17 | 18 | const asyncCredentials = { 19 | accessKeyId: 'GHJKLNB', 20 | secretAccessKey: 'hgfjhgfu6eru6rfjhgcu65iugbv', 21 | sessionToken: 'hfd875gh976087ykhvjgfd6569786pgkjhg9776' 22 | }; 23 | 24 | window.AWS = { 25 | config: {credentials} 26 | }; 27 | 28 | beforeEach(() => { 29 | module('angular-aws-apig', (_$httpProvider_, _APIGInterceptorProvider_) => { 30 | APIGInterceptorProvider = _APIGInterceptorProvider_; 31 | $httpProvider = _$httpProvider_; 32 | $httpProvider.interceptors.push('APIGInterceptor'); 33 | }); 34 | inject((_APIGInterceptor_, _$httpBackend_, _$http_, _$rootScope_) => { 35 | APIGInterceptor = _APIGInterceptor_; 36 | $httpBackend = _$httpBackend_; 37 | $http = _$http_; 38 | $rootScope = _$rootScope_; 39 | }) 40 | }); 41 | 42 | afterEach(inject(($httpBackend) => { 43 | $httpBackend.verifyNoOutstandingExpectation(); 44 | $httpBackend.verifyNoOutstandingRequest(); 45 | })); 46 | 47 | it('should load APIGInterceptorProvider', () => { 48 | expect(APIGInterceptorProvider).to.be.an('object'); 49 | }); 50 | 51 | it('should load APIGInterceptor', () => { 52 | expect(APIGInterceptor).to.be.an('object'); 53 | }); 54 | 55 | it('should be in http interceptors', () => { 56 | expect($httpProvider.interceptors).to.contain('APIGInterceptor'); 57 | }); 58 | 59 | describe('http GET request', () => { 60 | let headers; 61 | beforeEach(() => { 62 | $rootScope.bar = '54321'; 63 | APIGInterceptorProvider.config({ 64 | headers: {foo: '12345'} 65 | }); 66 | 67 | APIGInterceptorProvider.headersGetter = ($rootScope, request) => { 68 | request.headers.bar = $rootScope.bar; 69 | return request.headers; 70 | }; 71 | 72 | $httpBackend.expect('GET', 'https://api.fakeurl.com/some/path', null, (h) => { 73 | headers = h; 74 | return true; 75 | }).respond(200, {}); 76 | 77 | $http.get('https://api.fakeurl.com/some/path'); 78 | $httpBackend.flush(); 79 | }); 80 | 81 | it('should have foo header form config function', () => { 82 | expect(headers.foo).to.equal('12345'); 83 | }); 84 | 85 | it('should have bar header form headerGetter function', () => { 86 | expect(headers.bar).to.equal('54321'); 87 | }); 88 | 89 | it('should have correct SignedHeaders', () => { 90 | expect(headers.Authorization).to.contain('SignedHeaders=accept;bar;foo;host;x-amz-date'); 91 | }); 92 | 93 | it('should have correct accessKeyId', () => { 94 | expect(headers.Authorization).to.contain(credentials.accessKeyId); 95 | }); 96 | 97 | it('should have correct x-amz-security-token', () => { 98 | expect(headers['x-amz-security-token']).to.equal(credentials.sessionToken); 99 | }); 100 | 101 | it('should not have Content-Type header', () => { 102 | expect(headers['Content-Type']).to.be.an('undefined'); 103 | }); 104 | }); 105 | 106 | describe('http POST request', () => { 107 | let headers; 108 | beforeEach(() => { 109 | $httpBackend.expect('POST', 'https://api.fakeurl.com/some/path', {foo: 'bar'}, (h) => { 110 | headers = h; 111 | return true; 112 | }).respond(200, {}); 113 | 114 | $http.post('https://api.fakeurl.com/some/path', {foo: 'bar'}); 115 | $httpBackend.flush(); 116 | }); 117 | 118 | it('should have Content-Type header', () => { 119 | expect(headers['Content-Type']).to.equal('application/json;charset=utf-8'); 120 | }); 121 | 122 | it('should have correct SignedHeaders', () => { 123 | expect(headers.Authorization).to.contain('SignedHeaders=accept;content-type;host;x-amz-date'); 124 | }); 125 | }); 126 | 127 | it('credentialsGetter should work with promise', () => { 128 | let headers; 129 | APIGInterceptorProvider.credentialsGetter = ($q) => { 130 | return $q.when(asyncCredentials); 131 | }; 132 | 133 | $httpBackend.expect('GET', 'https://api.fakeurl.com/some/path?foo=bar', null, (h) => { 134 | headers = h; 135 | return true; 136 | }).respond(200, {}); 137 | 138 | $http.get('https://api.fakeurl.com/some/path', {params: {foo: 'bar'}}); 139 | $httpBackend.flush(); 140 | expect(headers['x-amz-security-token']).to.equal(asyncCredentials.sessionToken); 141 | }); 142 | 143 | describe('should work with regex specified', () => { 144 | beforeEach(() => { 145 | APIGInterceptorProvider.config({ 146 | urlRegex: 'base_url' 147 | }); 148 | }); 149 | 150 | it('and return correct headers when url matched', () => { 151 | let headers; 152 | $httpBackend.expect('GET', 'https://api.base_url.com/some/path', null, (h) => { 153 | headers = h; 154 | return true; 155 | }).respond(200, {}); 156 | 157 | $http.get('https://api.base_url.com/some/path'); 158 | $httpBackend.flush(); 159 | expect(headers['x-amz-security-token']).to.equal(credentials.sessionToken); 160 | }); 161 | 162 | it('and skip headers when url is not mathced', () => { 163 | let headers; 164 | $httpBackend.expect('GET', 'https://api.fakeurl.com/some/path', null, (h) => { 165 | headers = h; 166 | return true; 167 | }).respond(200, {}); 168 | 169 | $http.get('https://api.fakeurl.com/some/path'); 170 | $httpBackend.flush(); 171 | expect(headers['x-amz-security-token']).to.be.an('undefined'); 172 | }); 173 | }) 174 | }); --------------------------------------------------------------------------------