package tech.greenfield.vertx.irked.helpers;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import tech.greenfield.vertx.irked.auth.ParameterEncodedAuthorizationToken;
import tech.greenfield.vertx.irked.status.Unauthorized;

public class DigestAuthenticate extends Unauthorized {

	private static final long serialVersionUID = 1633008924546501215L;
	private static SecureRandom rand;
	
	static {
		try {
			rand = SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException e) { // shouldn't happen - every JVM must have this implementation
			rand = null;
		}
	}
	
	public DigestAuthenticate(String realm) {
		this(realm, "");
	}

	public DigestAuthenticate(String realm, String opaque) {
		this(realm, generateNonce("", TimeUnit.MINUTES.toMillis(5)), opaque, "MD5", true);
	}

	public DigestAuthenticate(String realm, boolean allowQopIntegrity) {
		this(realm, generateNonce("", TimeUnit.MINUTES.toSeconds(5)), "", "MD5", allowQopIntegrity);
	}

	public DigestAuthenticate(String realm, String opaque, boolean allowQopIntegrity) {
		this(realm, generateNonce("", TimeUnit.MINUTES.toSeconds(5)), opaque, "MD5", allowQopIntegrity);
	}

	public DigestAuthenticate(String realm, String nonce, String opaque, String algorithm) {
		this(realm, nonce, opaque, algorithm, true);
	}
	
	public DigestAuthenticate(String realm, String nonce, String opaque, String algorithm, boolean allowQopIntegrity) {
		addHeader("WWW-Authenticate", "Digest " + Stream.of(
				"realm=\"" + realm + "\"",
				"qop=\"auth" + (allowQopIntegrity ? ", auth-int" : "") + "\"",
				"algorithm=\"" + algorithm + "\"",
				"nonce=\"" + nonce + "\"",
				"opaque=\"" + opaque + "\""
				).collect(Collectors.joining(", ")));
	}

	public static String generateNonce(String tag, long expiry) {
		byte[] randdata = new byte[8];
		rand.nextBytes(randdata);
		String nonce = String.valueOf(System.currentTimeMillis() / 1000 + expiry) + ":" + tag + ":" + ParameterEncodedAuthorizationToken.toHex(randdata);
		try {
			return Base64.getEncoder().encodeToString(nonce.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) { // shouldn't happen as "UTF-8" is builtin
			return null;
		}
	}

}

@@ -43,53 +43,8 @@
 s;%0A%0A
-import java.io.UnsupportedEncodingException;%0A
 impo
@@ -253,16 +253,52 @@
 tream;%0A%0A
+import io.vertx.core.buffer.Buffer;%0A
 import t
@@ -2179,25 +2179,16 @@
 ddata);%0A
-%09%09try %7B%0A%09
 %09%09return
@@ -2223,21 +2223,36 @@
 oString(
+Buffer.buffer(
 nonce
+)
 .getByte
@@ -2257,125 +2257,11 @@
 tes(
-%22UTF-8%22));%0A%09%09%7D catch (UnsupportedEncodingException e) %7B // shouldn't happen as %22UTF-8%22 is builtin%0A%09%09%09return null;%0A%09%09%7D
+));
 %0A%09%7D%0A

use vert.x to get UTF8 bytes as it doesn't throw exceptions needlessly