# All files / src/crypt decrypter.js

42.62% Statements 26/61
17.86% Branches 5/28
20% Functions 2/10
43.33% Lines 26/60

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    10116x
    16x
    16x

    16x
    16x

    16x

    16x

    16x

    16x
    268x
    134x
    134x
    134x
    134x

    134x
    134x
    134x
    134x
    134x

    134x

    16x

    16x

    16x

    16x

    16x

    16x
     import AESCrypto from './aes-crypto';
    import FastAESKey from './fast-aes-key';
    import AESDecryptor from './aes-decryptor';

    import { ErrorTypes, ErrorDetails } from '../errors';
    import { logger } from '../utils/logger';

    import Event from '../events';

    import { getSelfScope } from '../utils/get-self-scope';

    // see https://stackoverflow.com/a/11237259/589493
    const global = getSelfScope(); // safeguard for code that might run both on worker and main thread

    class Decrypter {
      constructor (observer, config, { removePKCS7Padding = true } = {}) {
        this.logEnabled = true;
        this.observer = observer;
        this.config = config;
        this.removePKCS7Padding = removePKCS7Padding;
        // built in decryptor expects PKCS7 padding
        Eif (removePKCS7Padding) {
          try {
            const browserCrypto = global.crypto;
            Eif (browserCrypto) {
              this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
            }
          } catch (e) {}
        }
        this.disableWebCrypto = !this.subtle;
      }

      isSync () {
        return (this.disableWebCrypto && this.config.enableSoftwareAES);
      }

      decrypt (data, key, iv, callback) {
        if (this.disableWebCrypto && this.config.enableSoftwareAES) {
          if (this.logEnabled) {
            logger.log('JS AES decrypt');
            this.logEnabled = false;
          }
          let decryptor = this.decryptor;
          if (!decryptor) {
            this.decryptor = decryptor = new AESDecryptor();
          }

          decryptor.expandKey(key);
          callback(decryptor.decrypt(data, 0, iv, this.removePKCS7Padding));
        } else {
          if (this.logEnabled) {
            logger.log('WebCrypto AES decrypt');
            this.logEnabled = false;
          }
          const subtle = this.subtle;
          if (this.key !== key) {
            this.key = key;
            this.fastAesKey = new FastAESKey(subtle, key);
          }

          this.fastAesKey.expandKey()
            .then((aesKey) => {
              // decrypt using web crypto
              let crypto = new AESCrypto(subtle, iv);
              crypto.decrypt(data, aesKey)
                .catch((err) => {
                  this.onWebCryptoError(err, data, key, iv, callback);
                })
                .then((result) => {
                  callback(result);
                });
            })
            .catch((err) => {
              this.onWebCryptoError(err, data, key, iv, callback);
            });
        }
      }

      onWebCryptoError (err, data, key, iv, callback) {
        if (this.config.enableSoftwareAES) {
          logger.log('WebCrypto Error, disable WebCrypto API');
          this.disableWebCrypto = true;
          this.logEnabled = true;
          this.decrypt(data, key, iv, callback);
        } else {
          logger.error(`decrypting error : ${err.message}`);
          this.observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_DECRYPT_ERROR, fatal: true, reason: err.message });
        }
      }

      destroy () {
        let decryptor = this.decryptor;
        if (decryptor) {
          decryptor.destroy();
          this.decryptor = undefined;
        }
      }
    }

    export default Decrypter;