open static method

DVSignedBundle open(
  1. String envelope, {
  2. required List<int> publicKey,
  3. bool requireContentVersion = false,
})

Verifies envelope against publicKey and returns what it states.

The statement is parsed from the exact bytes the signature covers, and those bytes must be canonical: a payload with a duplicated key means one thing to one parser and another to the next. With requireContentVersion the bundle's version must be its content digest.

Throws DVSignedBundleException for anything else, including a bundle that was never signed at all.

Implementation

static DVSignedBundle open(
  String envelope, {
  required List<int> publicKey,
  bool requireContentVersion = false,
}) {
  final Object? outer;
  try {
    outer = jsonDecode(envelope);
  } on FormatException {
    throw const DVSignedBundleException('The body is not a bundle at all.');
  }
  if (outer is! Map ||
      outer['format'] != dvSignedBundleFormat ||
      outer['payload'] is! String ||
      outer['signature'] is! String) {
    throw const DVSignedBundleException(
      'This bundle is not signed, and only signed bundles are loaded.',
    );
  }

  final Uint8List payload;
  final Uint8List signature;
  try {
    payload = dvWebPushBase64Decode(outer['payload'] as String);
    signature = dvWebPushBase64Decode(outer['signature'] as String);
  } on FormatException {
    throw const DVSignedBundleException(
      'The envelope\'s payload or signature is not base64url.',
    );
  }
  if (!_verifyEs256(payload, signature, publicKey)) {
    throw const DVSignedBundleException(
      'The signature does not verify against the paired key. The bundle '
      'was sealed by another key or altered after sealing.',
    );
  }

  final String text;
  final Object? statement;
  try {
    text = utf8.decode(payload);
    statement = jsonDecode(text);
  } on FormatException {
    throw const DVSignedBundleException('The signed payload is not JSON.');
  }
  if (jsonEncode(statement) != text) {
    throw const DVSignedBundleException(
      'The signed payload is not canonical JSON (a key is duplicated or '
      'spaced differently), so it could be read two ways.',
    );
  }
  if (statement is! Map || statement['format'] != dvSignedBundleFormat) {
    throw const DVSignedBundleException(
      'The signed payload does not name the bundle format.',
    );
  }
  final Object? bundle = statement['bundle'];
  if (bundle is! Map ||
      bundle['version'] is! String ||
      (bundle['version'] as String).isEmpty) {
    throw const DVSignedBundleException(
      'The signed payload carries no versioned bundle.',
    );
  }
  final Map<String, Object?> typed = bundle.cast<String, Object?>();
  if (requireContentVersion &&
      typed['version'] != dvDevClientBundleVersion(typed)) {
    throw DVSignedBundleException(
      'The bundle\'s version "${typed['version']}" is not the digest of '
      'its content, so a changed bundle could be taken for one already '
      'applied.',
    );
  }

  final Object? channel = statement['channel'];
  final Object? sequence = statement['sequence'];
  final Object? requires = statement['requires'];
  try {
    return DVSignedBundle._(
      bundle: typed,
      channel: channel is String ? channel : null,
      sequence: sequence is int ? sequence : null,
      requires: requires is Map
          ? DVDevClientManifest.fromJson(requires.cast<String, Object?>())
          : null,
    );
  } on FormatException catch (error) {
    throw DVSignedBundleException(error.message);
  }
}