public ConfigAuthorizedAppRepository(IConfiguration config)
 {
     Android                = new AuthorizedAppInformation();
     Android.Platform       = "android";
     Android.AllowedRegions = config.SupportRegions();
     Android.PackageName    = config.AndroidPackageName();
     iOS                       = new AuthorizedAppInformation();
     iOS.Platform              = "ios";
     iOS.AllowedRegions        = config.SupportRegions();
     iOS.PackageName           = config.iOSBundleId();
     iOS.DeviceCheckKeyId      = config.iOSDeviceCheckKeyId();
     iOS.DeviceCheckTeamId     = config.iOSDeviceCheckTeamId();
     iOS.DeviceCheckPrivateKey = config.iOSDeviceCheckPrivateKey();
 }
Exemplo n.º 2
0
        /// <summary>
        /// Validation iOS
        /// </summary>
        /// <param name="param">subumission parameter</param>
        /// <returns>True when successful.</returns>
        /// <remarks>
        /// https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data
        /// </remarks>
        public async Task <bool> Validation(IAppleDeviceVerification deviceVerification, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            var payload = new ApplePayload()
            {
                DeviceToken = deviceVerification.DeviceToken,
                Timestamp   = requestTime.ToUnixTimeMilliseconds()
            };

            using (var sha = SHA256.Create())
            {
                payload.TransactionId = Convert.ToBase64String(
                    sha.ComputeHash(Encoding.UTF8.GetBytes(deviceVerification.TransactionIdSeed))
                    );
            }

            Logger.LogInformation($"{nameof(Validation)} DeviceCheckKeyId:{app.DeviceCheckKeyId} DeviceCheckTeamId:{app.DeviceCheckTeamId} DeviceCheckPrivateKey:{app.DeviceCheckPrivateKey}");

            var jwt = GenerateClientSecretJWT(requestTime, app.DeviceCheckKeyId, app.DeviceCheckTeamId, app.DeviceCheckPrivateKey);

            var payloadJson = JsonConvert.SerializeObject(payload);

            Logger.LogInformation($"{nameof(Validation)} payload:{payloadJson} ");
            var request = new HttpRequestMessage(HttpMethod.Post, UrlApple);

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
            request.Content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
            try
            {
                var response = await ClientApple.SendAsync(request);

                if (!response.IsSuccessStatusCode)
                {
                    Logger.LogWarning($"iOS device check failed.\r\n{nameof(HttpRequestMessage)} : {request}\r\n{nameof(HttpResponseMessage)} : {response}");
                }

                return(response.StatusCode == System.Net.HttpStatusCode.OK);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, $"{nameof(Validation)}");
                throw;
            }
        }
        /// <summary>
        /// Validation iOS
        /// </summary>
        /// <param name="param">subumission parameter</param>
        /// <returns>True when successful.</returns>
        /// <remarks>
        /// https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data
        /// </remarks>
        public async Task <bool> Validation(DiagnosisSubmissionParameter param, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            var payload = new ApplePayload()
            {
                DeviceToken = param.DeviceVerificationPayload,
                Timestamp   = requestTime.ToUnixTimeMilliseconds()
            };

            var keysText = string.Empty;

            if (param is V1DiagnosisSubmissionParameter)
            {
                keysText = (param as V1DiagnosisSubmissionParameter).Keys
                           .OrderBy(_ => _.KeyData)
                           .Select(_ => _.KeyData)
                           .Aggregate((a, b) => a + b);
            }
            else
            {
                keysText = param.Keys
                           .OrderBy(_ => _.KeyData)
                           .Select(_ => _.KeyData)
                           .Aggregate((a, b) => a + b);
            }

            using (var sha = System.Security.Cryptography.SHA256.Create())
            {
                var value = System.Text.Encoding.UTF8.GetBytes(param.AppPackageName + keysText + string.Join(',', param.Regions));
                payload.TransactionId = Convert.ToBase64String(sha.ComputeHash(value));
            }

            Logger.LogInformation($"{nameof(Validation)} DeviceCheckKeyId:{app.DeviceCheckKeyId} DeviceCheckTeamId:{app.DeviceCheckTeamId} DeviceCheckPrivateKey:{app.DeviceCheckPrivateKey}");

            var jwt = GenerateClientSecretJWT(requestTime, app.DeviceCheckKeyId, app.DeviceCheckTeamId, app.DeviceCheckPrivateKey);

            var payloadJson = JsonConvert.SerializeObject(payload);

            Logger.LogInformation($"{nameof(Validation)} payload:{payloadJson} ");
            var request = new HttpRequestMessage(HttpMethod.Post, UrlApple);

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
            request.Content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
            try
            {
                var response = await ClientApple.SendAsync(request);

                if (!response.IsSuccessStatusCode)
                {
                    var responseBody = await response.Content.ReadAsStringAsync();

                    Logger.LogWarning($"POST {UrlApple} {response.StatusCode} {response.ReasonPhrase} {responseBody}");
                }

                //switch (response.StatusCode)
                //{
                //    // 200 OK:                  The transaction was successful
                //    // 200 Bit State Not Found: The bit state wasn't found
                //    case System.Net.HttpStatusCode.OK:
                //        if (response.ReasonPhrase == "OK") return true;

                //        break;
                //    //
                //    default:
                //        break;
                //}
                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    return(false);
                }

                return(true);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, $"{nameof(Validation)}");
                throw;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Validation Android
        /// </summary>
        /// <returns>True when successful.</returns>
        public bool Validation(IAndroidDeviceVerification deviceVerification, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            byte[] expectedNonce = GetSha256(deviceVerification.ClearText);
            var    claims        = ParsePayload(deviceVerification.JwsPayload);

            // Validate the nonce
            if (Convert.ToBase64String(claims.Nonce) != Convert.ToBase64String(expectedNonce))
            {
                return(false);
            }

            // Validate time interval
            var now = requestTime.ToUnixTimeMilliseconds();

            if (app.SafetyNetPastTimeSeconds > 0)
            {
                var minTime = now - (app.SafetyNetPastTimeSeconds * 1000);
                if (claims.TimestampMilliseconds < minTime)
                {
                    return(false);
                }
            }
            if (app.SafetyNetFutureTimeSeconds > 0)
            {
                var minTime = now + (app.SafetyNetFutureTimeSeconds * 1000);
                if (claims.TimestampMilliseconds > minTime)
                {
                    return(false);
                }
            }

            // Validate certificate
            if (app.SafetyNetApkDigestSha256?.Length > 0)
            {
                var apkSha = Convert.ToBase64String(claims.ApkCertificateDigestSha256);
                if (!app.SafetyNetApkDigestSha256.Contains(apkSha))
                {
                    return(false);
                }
            }

            // Validate integrity
            if (app.SafetyNetCtsProfileMatch)
            {
                if (!claims.CtsProfileMatch)
                {
                    return(false);
                }
            }
            if (app.SafetyNetBasicIntegrity)
            {
                if (!claims.BasicIntegrity)
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Validation iOS
        /// </summary>
        /// <param name="param">subumission parameter</param>
        /// <returns>True when successful.</returns>
        /// <remarks>
        /// https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data
        /// </remarks>
        public async Task <bool> Validation(IAppleDeviceVerification deviceVerification, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            var payload = new ApplePayload()
            {
                DeviceToken = deviceVerification.DeviceToken,
                Timestamp   = requestTime.ToUnixTimeMilliseconds()
            };

            using (var sha = SHA256.Create())
            {
                payload.TransactionId = Convert.ToBase64String(
                    sha.ComputeHash(Encoding.UTF8.GetBytes(deviceVerification.TransactionIdSeed))
                    );
            }

            Logger.LogInformation($"{nameof(Validation)} DeviceCheckKeyId:{app.DeviceCheckKeyId} DeviceCheckTeamId:{app.DeviceCheckTeamId} DeviceCheckPrivateKey:{app.DeviceCheckPrivateKey}");

            var jwt = GenerateClientSecretJWT(requestTime, app.DeviceCheckKeyId, app.DeviceCheckTeamId, app.DeviceCheckPrivateKey);

            var payloadJson = JsonConvert.SerializeObject(payload);

            Logger.LogInformation($"{nameof(Validation)} payload:{payloadJson} ");
            var request = new HttpRequestMessage(HttpMethod.Post, UrlApple);

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
            request.Content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
            try
            {
                var response = await ClientApple.SendAsync(request);

                if (!response.IsSuccessStatusCode)
                {
                    var responseBody = await response.Content.ReadAsStringAsync();

                    Logger.LogWarning($"iOS device check failed.\r\n{nameof(HttpRequestMessage)} : {request}\r\n{nameof(HttpResponseMessage)} : {response}");
                }

                //switch (response.StatusCode)
                //{
                //    // 200 OK:                  The transaction was successful
                //    // 200 Bit State Not Found: The bit state wasn't found
                //    case System.Net.HttpStatusCode.OK:
                //        if (response.ReasonPhrase == "OK") return true;

                //        break;
                //    //
                //    default:
                //        break;
                //}
                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    // FIXME: When call iOS Device check, return error sometimes, Until the cause is known, ignored device check
                    return(true);
                }

                return(true);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, $"{nameof(Validation)}");
                throw;
            }
        }
        /// <summary>
        /// Validation Android
        /// </summary>
        /// <param name="param">subumission parameter</param>
        /// <returns>True when successful.</returns>
        public async Task <bool> Validation(DiagnosisSubmissionParameter param, byte[] expectedNonce, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            var claims = await ParsePayloadAsync(param.DeviceVerificationPayload);

            // Validate the nonce
            if (Convert.ToBase64String(claims.Nonce) != Convert.ToBase64String(expectedNonce))
            {
                return(false);
            }

            // Validate time interval
            var now = requestTime.ToUnixTimeMilliseconds();

            if (app.SafetyNetPastTimeSeconds > 0)
            {
                var minTime = now - (app.SafetyNetPastTimeSeconds * 1000);
                if (claims.TimestampMilliseconds < minTime)
                {
                    return(false);
                }
            }
            if (app.SafetyNetFutureTimeSeconds > 0)
            {
                var minTime = now + (app.SafetyNetFutureTimeSeconds * 1000);
                if (claims.TimestampMilliseconds > minTime)
                {
                    return(false);
                }
            }

            // Validate certificate
            if (app.SafetyNetApkDigestSha256?.Length > 0)
            {
                var apkSha = Convert.ToBase64String(claims.ApkCertificateDigestSha256);
                if (!app.SafetyNetApkDigestSha256.Contains(apkSha))
                {
                    return(false);
                }
            }

            // Validate integrity
            if (app.SafetyNetCtsProfileMatch)
            {
                if (!claims.CtsProfileMatch)
                {
                    return(false);
                }
            }
            if (app.SafetyNetBasicIntegrity)
            {
                if (!claims.BasicIntegrity)
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Validation iOS
        /// </summary>
        /// <param name="param">subumission parameter</param>
        /// <returns>True when successful.</returns>
        /// <remarks>
        /// https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data
        /// </remarks>
        public async Task <bool> Validation(DiagnosisSubmissionParameter param, DateTimeOffset requestTime, AuthorizedAppInformation app)
        {
            var payload = new ApplePayload()
            {
                DeviceToken = param.DeviceVerificationPayload,
                Timestamp   = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            };

            var keysText = param.Keys
                           .OrderBy(_ => _.KeyData)
                           .Select(_ => _.KeyData)
                           .Aggregate((a, b) => a + b);

            using (var sha = System.Security.Cryptography.SHA256.Create())
            {
                var value = System.Text.Encoding.UTF8.GetBytes(param.AppPackageName + keysText + string.Join(',', param.Regions));
                payload.TransactionId = Convert.ToBase64String(sha.ComputeHash(value));
            }

            var jwt = GenerateClientSecretJWT(requestTime, app.DeviceCheckKeyId, app.DeviceCheckTeamId, app.DeviceCheckPrivateKey);

            var content = new StringContent(JsonConvert.SerializeObject(payload));
            var request = new HttpRequestMessage(HttpMethod.Post, UrlApple);

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
            var response = await ClientApple.SendAsync(request);

            //switch (response.StatusCode)
            //{
            //    // 200 OK:                  The transaction was successful
            //    // 200 Bit State Not Found: The bit state wasn't found
            //    case System.Net.HttpStatusCode.OK:
            //        if (response.ReasonPhrase == "OK") return true;

            //        break;
            //    //
            //    default:
            //        break;
            //}
            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                return(false);
            }

            return(true);
        }