signRequest method

  1. @protected
String? signRequest(
  1. BaseRequest request, {
  2. Digest? contentSha256,
  3. bool preSignedUrl = false,
  4. int expires = 86400,
})
inherited

Implementation

@protected
String? signRequest(http.BaseRequest request,
    {Digest? contentSha256, bool preSignedUrl = false, int expires = 86400}) {
  // Build canonical request
  String httpMethod = request.method;
  String canonicalURI = request.url.path;
  String host = request.url.host;
  // String service = 's3';

  DateTime date = new DateTime.now().toUtc();
  String dateIso8601 = date.toIso8601String();
  dateIso8601 = dateIso8601
          .substring(0, dateIso8601.indexOf('.'))
          .replaceAll(':', '')
          .replaceAll('-', '') +
      'Z';
  String dateYYYYMMDD = date.year.toString().padLeft(4, '0') +
      date.month.toString().padLeft(2, '0') +
      date.day.toString().padLeft(2, '0');

  // dateIso8601 = "20130524T000000Z";
  // dateYYYYMMDD = "20130524";
  // hashedPayload = null;
  String hashedPayloadStr =
      contentSha256 == null ? 'UNSIGNED-PAYLOAD' : '$contentSha256';

  String credential =
      '${accessKey}/${dateYYYYMMDD}/${region}/${service}/aws4_request';

  // Build canonical headers string
  Map<String, String?> headers = new Map<String, String?>();
  if (!preSignedUrl) {
    request.headers['x-amz-date'] = dateIso8601; // Set date in header
    if (contentSha256 != null) {
      request.headers['x-amz-content-sha256'] =
          hashedPayloadStr; // Set payload hash in header
    }
    request.headers.keys.forEach((String name) =>
        (headers[name.toLowerCase()] = request.headers[name]));
  }
  headers['host'] = host; // Host is a builtin header
  List<String> headerNames = headers.keys.toList()..sort();
  String canonicalHeaders =
      headerNames.map((s) => '${s}:${_trimAll(headers[s]!)}' + '\n').join();

  String signedHeaders = headerNames.join(';');

  // Build canonical query string
  Map<String, String> queryParameters = new Map<String, String>()
    ..addAll(request.url.queryParameters);
  if (preSignedUrl) {
    // Add query parameters
    queryParameters['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
    queryParameters['X-Amz-Credential'] = credential;
    queryParameters['X-Amz-Date'] = dateIso8601;
    queryParameters['X-Amz-Expires'] = expires.toString();
    if (contentSha256 != null) {
      queryParameters['X-Amz-Content-Sha256'] = hashedPayloadStr;
    }
    queryParameters['X-Amz-SignedHeaders'] = signedHeaders;
  }
  List<String> queryKeys = queryParameters.keys.toList()..sort();
  String canonicalQueryString = queryKeys
      .map((s) => '${_uriEncode(s)}=${_uriEncode(queryParameters[s]!)}')
      .join('&');

  if (preSignedUrl) {
    // TODO: Specific payload upload with pre-signed URL not supported on DigitalOcean?
    hashedPayloadStr = 'UNSIGNED-PAYLOAD';
  }

  // Sign headers
  String canonicalRequest =
      '${httpMethod}\n${canonicalURI}\n${canonicalQueryString}\n${canonicalHeaders}\n${signedHeaders}\n$hashedPayloadStr';
  // print('\n>>>>>> canonical request \n' + canonicalRequest + '\n<<<<<<\n');

  Digest canonicalRequestHash = sha256.convert(utf8.encode(
      canonicalRequest)); //_hmacSha256.convert(utf8.encode(canonicalRequest));

  String stringToSign =
      'AWS4-HMAC-SHA256\n${dateIso8601}\n${dateYYYYMMDD}/${region}/${service}/aws4_request\n$canonicalRequestHash';
  // print('\n>>>>>> string to sign \n' + stringToSign + '\n<<<<<<\n');

  Digest dateKey = new Hmac(sha256, utf8.encode("AWS4${secretKey}"))
      .convert(utf8.encode(dateYYYYMMDD));
  Digest dateRegionKey =
      new Hmac(sha256, dateKey.bytes).convert(utf8.encode(region!));
  Digest dateRegionServiceKey =
      new Hmac(sha256, dateRegionKey.bytes).convert(utf8.encode(service));
  Digest signingKey = new Hmac(sha256, dateRegionServiceKey.bytes)
      .convert(utf8.encode("aws4_request"));

  Digest signature =
      new Hmac(sha256, signingKey.bytes).convert(utf8.encode(stringToSign));

  // Set signature in header
  request.headers['Authorization'] =
      'AWS4-HMAC-SHA256 Credential=${credential}, SignedHeaders=${signedHeaders}, Signature=$signature';

  if (preSignedUrl) {
    queryParameters['X-Amz-Signature'] = '$signature';
    return request.url.replace(queryParameters: queryParameters).toString();
  } else {
    return null;
  }
}