package com.airlock.iam.factor.application.configuration.fido;

import com.airlock.iam.factor.domain.model.fido.FidoAndroidApkKeyHashOrigin;
import com.airlock.iam.factor.domain.model.fido.FidoOrigin;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.license.PluginLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.PropertyConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(
   displayName = "FIDO Android App Origin",
   description = "<p>A hash from an Android native app WebAuthn origin. Android native apps send origins of the form <code>android:apk-key-hash:&lt;hash&gt;</code>.\n\nThe hash has to be configured in at least the following places to tie together the involved app, IAM and Google API Servers:\n\n<ul>\n\t<li>In this plugin.</li>\n\t<li>Under <code>https://&lt;Relying Party ID&gt;/.well-known/assetlinks.json</code> in the field <code>sha256_cert_fingerprints</code> as specified by the Android App Link documentation.\n</ul>\nThere is no mechanism in IAM to host or automatically generate the <code>assetlinks.json</code>.</li>\n"
)
@PluginLicenseRestriction(moduleAffiliation = "FIDO")
public final class FidoAndroidApkKeyHashOriginConfig implements FidoAdditionalOriginConfig {
   @StringProperty(
      displayName = "APK Key Hash",
      description = "The URL-safe Base64 encoded SHA-256 hash.\n\nThe hash can be obtained in a few different ways:\n<ul>\n\t<li>Release keystore with e.g. <code>keytool -list -v -keystore app-release.keystore -alias my-signing-key</code>.</li>\n\t<li>A signed apk with <code>apksigner verify --print-certs app-release.apk</code></li>\n\t<li>In Android Studio use the Gradle task <code>signingReport</code></li>\n\t<li>In the Google Play Console: Go to your app &gt; Setup &gt; App integrity &gt; App signing.</li>\n</ul>\nUsually it is a hex value that has to be converted to the URL-safe Base64 encoding.\n\n<p>You can also use the IAM logs during integration to obtain the hash, which already is in the required format. If you do not have the correct hash configured in the IAM\nyou will see the following DEBUG log message:</p>\n<p><code>No match: android:apk-key-hash:&lt;your_hash_here&gt; != https://</code></p>\n\nConsult your app developers or the Airlock documentation for more details on the android APK hash and Asset Link mechanism.\n",
      optional = false,
      exampleValues = "pRE0AbGoJZmZmYnJ6dP3aI7Yd0Wf9x8bqLQvWn1tYIa"
   )
   private String apkKeyHash;
   static final String APK_KEY_HASH_FIELD = "apkKeyHash";

   @ConfigurationValidator
   static void checkApkKeyHashIsValid(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws PropertyConfigurationException {
      String configuredApkKeyHash = StringPropertyValueReader.effectiveStringConfigValue(config, "apkKeyHash", env, context);
      if (!FidoAndroidApkKeyHashOrigin.isValidAndroidApkKeyHash(configuredApkKeyHash)) {
         throw new PropertyConstraintViolationException(
            "apkKeyHash", config, env, context, "The APK key hash must be the URL-safe Base64 encoding of a SHA-256 digest (43 characters, no padding)."
         );
      }
   }

   @Override
   public FidoOrigin getWebAuthnOrigin() {
      return new FidoAndroidApkKeyHashOrigin(this.apkKeyHash);
   }

   @SuppressFBWarnings(justification = "generated code")
   public static FidoAndroidApkKeyHashOriginConfig.FidoAndroidApkKeyHashOriginConfigBuilder builder() {
      return new FidoAndroidApkKeyHashOriginConfig.FidoAndroidApkKeyHashOriginConfigBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public FidoAndroidApkKeyHashOriginConfig() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public FidoAndroidApkKeyHashOriginConfig(String apkKeyHash) {
      this.apkKeyHash = apkKeyHash;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class FidoAndroidApkKeyHashOriginConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String apkKeyHash;

      @SuppressFBWarnings(justification = "generated code")
      FidoAndroidApkKeyHashOriginConfigBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public FidoAndroidApkKeyHashOriginConfig.FidoAndroidApkKeyHashOriginConfigBuilder apkKeyHash(String apkKeyHash) {
         this.apkKeyHash = apkKeyHash;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public FidoAndroidApkKeyHashOriginConfig build() {
         return new FidoAndroidApkKeyHashOriginConfig(this.apkKeyHash);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "FidoAndroidApkKeyHashOriginConfig.FidoAndroidApkKeyHashOriginConfigBuilder(apkKeyHash=" + this.apkKeyHash + ")";
      }
   }
}
