package com.atlassian.bitbucket.ssh.utils;

import com.atlassian.bitbucket.ssh.util.KeyUtils;
import org.junit.Test;

import java.security.PublicKey;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

public final class KeyUtilsTest {

    /* RSA test data */
    private final String SAMPLE_RSA_ENCODED_KEY =
            "AAAAB3NzaC1yc2EAAAABIwAAAQEAwQ6EygyBdZwLgHxt2CDXypmlZyOtfWwPTMMTfX29PmLqcGrsLJmXY/A5RawENKRy9"
                    + "saaPPgsyml8dvnjSDqY1H5s7P3K62twM9d0cbME1nJc8xTt8krCQqHUW4UZ4rRfjYTH7XoF89LmBxHPDWIz+k9JAgMutHPr6S4k"
                    + "cN6bCnuX/tA3wArAJ7+EXLRZATKUAm2eMPJxRWA9N7WQ5KUHfY+KjzXwv0xdVBNnO6pLpb9V4Ht9vn3LKrEFnb/1SWnh5hdjTnn"
                    + "S7VKj+qUYNh4mEt+Yvi3UchtR3cLbRhC1BpTtbmRu+AccUTnWgRIXelRXXwnb7GPs8DvtvxHvXxv0YQ==";

    private final String SAMPLE_RSA_ENCODED_KEY_WITH_WHITESPACE =
            "AAAAB3NzaC1yc2EAAAABIwAAAQEAwQ6EygyBdZwLgHxt2CDXypmlZyOtfWwPTMMTfX29PmLqcGrsLJmXY/A5RawENKRy9"
                    + "  saaPPgsyml8dvnjSDqY1H5s7P3K62twM9d0cbME1nJc8xTt8krCQqHUW4UZ4rRfjYTH7XoF89LmBxHPDWIz+k9JAgMutHPr6S4k"
                    + "\ncN6bCnuX/tA3wArAJ7+EXLRZATKUAm2eMPJxRWA9N7WQ5KUHfY+KjzXwv0xdVBNnO6pLpb9V4Ht9vn3LKrEFnb/1SWnh5hdjTnn"
                    + "\tS7VKj+qUYNh4mEt+Yvi3UchtR3cLbRhC1BpTtbmRu+AccUTnWgRIXelRXXwnb7GPs8DvtvxHvXxv0YQ==" +
                    "\n";

    private final String SAMPLE_RSA_KEY = "ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " test@test.local";
    private final String SAMPLE_RSA_KEY_FINGERPRINT = "7c429782558756e9458f6f095b688301";
    private final String SAMPLE_RSA_KEY_WITH_WHITESPACE = "ssh-rsa " + SAMPLE_RSA_ENCODED_KEY_WITH_WHITESPACE + "test@test.local";

    private final byte[] SAMPLE_ENCODED_RSA_KEY
            = new byte[]{48, -126, 1, 32, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 13, 0, 48, -126, 1, 8, 2, -126, 1, 1, 0,
            -63, 14, -124, -54, 12, -127, 117, -100, 11, -128, 124, 109, -40, 32, -41, -54, -103, -91, 103, 35, -83, 125, 108, 15, 76, -61,
            19, 125, 125, -67, 62, 98, -22, 112, 106, -20, 44, -103, -105, 99, -16, 57, 69, -84, 4, 52, -92, 114, -10, -58, -102, 60, -8, 44, -54,
            105, 124, 118, -7, -29, 72, 58, -104, -44, 126, 108, -20, -3, -54, -21, 107, 112, 51, -41, 116, 113, -77, 4, -42, 114, 92, -13, 20, -19,
            -14, 74, -62, 66, -95, -44, 91, -123, 25, -30, -76, 95, -115, -124, -57, -19, 122, 5, -13, -46, -26, 7, 17, -49, 13, 98, 51, -6, 79, 73,
            2, 3, 46, -76, 115, -21, -23, 46, 36, 112, -34, -101, 10, 123, -105, -2, -48, 55, -64, 10, -64, 39, -65, -124, 92, -76, 89, 1, 50, -108,
            2, 109, -98, 48, -14, 113, 69, 96, 61, 55, -75, -112, -28, -91, 7, 125, -113, -118, -113, 53, -16, -65, 76, 93, 84, 19, 103, 59, -86, 75,
            -91, -65, 85, -32, 123, 125, -66, 125, -53, 42, -79, 5, -99, -65, -11, 73, 105, -31, -26, 23, 99, 78, 121, -46, -19, 82, -93, -6, -91, 24,
            54, 30, 38, 18, -33, -104, -66, 45, -44, 114, 27, 81, -35, -62, -37, 70, 16, -75, 6, -108, -19, 110, 100, 110, -8, 7, 28, 81, 57, -42, -127,
            18, 23, 122, 84, 87, 95, 9, -37, -20, 99, -20, -16, 59, -19, -65, 17, -17, 95, 27, -12, 97, 2, 1, 35};

    /* DSA test data */
    private final String SAMPLE_DSA_KEY
            = "ssh-dss AAAAB3NzaC1kc3MAAACBAPTvBn90k6vSAIu1djPtyGRY/uvhFfCfFICfO4q1wwbEagIiQ30yyy9DoTvkFpitQFGdy3q/U"
            + "y8pc0sG2pFuPe3jCLgEzX9naqc6ScjYxG+68m7tAxpEhkEr+1kZqkuSRauzUKdUvFL4zn0G4Qhhijo6uK/dLCmJMa5upsviQtHd"
            + "AAAAFQDbxnS00Z+tAAjIODrARmiM7Tp2JwAAAIEAsDnOKlg3GcGjtYF7JuBgzDitDraej4mQbNN0u8csoVauyN91mnhH83txkMW"
            + "mJpa0TawaDYwaT9jt+a6k0H4J8uEkWBuxkVY0tQWLOt0LI0dgPAPHyWgnVJqWzvfBcLLFJ8zK6gv7/O17007Zi0uDJ5+yEyKA2J"
            + "894SreATKOnVIAAACAEt8uDlDpWFzEnu8wH0bFIOKy0A5zQ7ojDAn7tHjYJgLdUFyXVK/62WAg1CaJYou5LH0Xhx/MeA/mGhyjp"
            + "9Yh1I475G83qmVG/G25fzsF5LoEnsVQ8RwwZ3n5xpJLc1G/pcxfRHUd5Ym8+2W8qdA7ZUXAHLOHMMyAqAab+KHEEJw= test@test.local";
    private final String SAMPLE_DSA_KEY_FINGERPRINT = "37bd66197e36ab8c59d21702e6ef749a";

    private final byte[] SAMPLE_ENCODED_DSA_KEY
            = new byte[]{48, -126, 1, -73, 48, -126, 1, 44, 6, 7, 42, -122, 72, -50, 56, 4, 1, 48, -126, 1, 31, 2, -127, -127, 0, -12, -17, 6, 127,
            116, -109, -85, -46, 0, -117, -75, 118, 51, -19, -56, 100, 88, -2, -21, -31, 21, -16, -97, 20, -128, -97, 59, -118, -75, -61, 6, -60,
            106, 2, 34, 67, 125, 50, -53, 47, 67, -95, 59, -28, 22, -104, -83, 64, 81, -99, -53, 122, -65, 83, 47, 41, 115, 75, 6, -38, -111, 110, 61,
            -19, -29, 8, -72, 4, -51, 127, 103, 106, -89, 58, 73, -56, -40, -60, 111, -70, -14, 110, -19, 3, 26, 68, -122, 65, 43, -5, 89, 25, -86,
            75, -110, 69, -85, -77, 80, -89, 84, -68, 82, -8, -50, 125, 6, -31, 8, 97, -118, 58, 58, -72, -81, -35, 44, 41, -119, 49, -82, 110, -90,
            -53, -30, 66, -47, -35, 2, 21, 0, -37, -58, 116, -76, -47, -97, -83, 0, 8, -56, 56, 58, -64, 70, 104, -116, -19, 58, 118, 39, 2, -127,
            -127, 0, -80, 57, -50, 42, 88, 55, 25, -63, -93, -75, -127, 123, 38, -32, 96, -52, 56, -83, 14, -74, -98, -113, -119, -112, 108, -45,
            116, -69, -57, 44, -95, 86, -82, -56, -33, 117, -102, 120, 71, -13, 123, 113, -112, -59, -90, 38, -106, -76, 77, -84, 26, 13, -116, 26,
            79, -40, -19, -7, -82, -92, -48, 126, 9, -14, -31, 36, 88, 27, -79, -111, 86, 52, -75, 5, -117, 58, -35, 11, 35, 71, 96, 60, 3, -57, -55,
            104, 39, 84, -102, -106, -50, -9, -63, 112, -78, -59, 39, -52, -54, -22, 11, -5, -4, -19, 123, -45, 78, -39, -117, 75, -125, 39, -97,
            -78, 19, 34, -128, -40, -97, 61, -31, 42, -34, 1, 50, -114, -99, 82, 3, -127, -124, 0, 2, -127, -128, 18, -33, 46, 14, 80, -23, 88, 92,
            -60, -98, -17, 48, 31, 70, -59, 32, -30, -78, -48, 14, 115, 67, -70, 35, 12, 9, -5, -76, 120, -40, 38, 2, -35, 80, 92, -105, 84, -81, -6,
            -39, 96, 32, -44, 38, -119, 98, -117, -71, 44, 125, 23, -121, 31, -52, 120, 15, -26, 26, 28, -93, -89, -42, 33, -44, -114, 59, -28, 111,
            55, -86, 101, 70, -4, 109, -71, 127, 59, 5, -28, -70, 4, -98, -59, 80, -15, 28, 48, 103, 121, -7, -58, -110, 75, 115, 81, -65, -91, -52,
            95, 68, 117, 29, -27, -119, -68, -5, 101, -68, -87, -48, 59, 101, 69, -64, 28, -77, -121, 48, -52, -128, -88, 6, -101, -8, -95, -60, 16,
            -100};

    /* ECDSA test data */
    private final String SAMPLE_ECDSA_KEY
            = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA8zAbK7QQlTXPIUsSb9hpULj7/c"
            + "HNEXZFQas4lrOeWfxKPQTr67Omeuk3RZPbeSH2EiixowxLiK91yHlRP2Two= test@test.local";
    private final String SAMPLE_ECDSA_KEY_FINGERPRINT = "f0003082b57396a58da00d93a3c1d995";

    private final byte[] SAMPLE_ENCODED_ECDSA_KEY
            = new byte[]{48, -126, 1, 51, 48, -127, -20, 6, 7, 42, -122, 72, -50, 61, 2, 1, 48, -127, -32, 2, 1, 1, 48,
            44, 6, 7, 42, -122, 72, -50, 61, 1, 1, 2, 33, 0, -1, -1, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, 68, 4, 32, -1, -1, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, 4, 32, 90, -58, 53, -40, -86, 58,
            -109, -25, -77, -21, -67, 85, 118, -104, -122, -68, 101, 29, 6, -80, -52, 83, -80, -10, 59, -50, 60, 62, 39,
            -46, 96, 75, 4, 65, 4, 107, 23, -47, -14, -31, 44, 66, 71, -8, -68, -26, -27, 99, -92, 64, -14, 119, 3, 125,
            -127, 45, -21, 51, -96, -12, -95, 57, 69, -40, -104, -62, -106, 79, -29, 66, -30, -2, 26, 127, -101, -114,
            -25, -21, 74, 124, 15, -98, 22, 43, -50, 51, 87, 107, 49, 94, -50, -53, -74, 64, 104, 55, -65, 81, -11, 2,
            33, 0, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -68, -26, -6, -83, -89, 23, -98, -124,
            -13, -71, -54, -62, -4, 99, 37, 81, 2, 1, 1, 3, 66, 0, 4, 15, 51, 1, -78, -69, 65, 9, 83, 92, -14, 20, -79,
            38, -3, -122, -107, 11, -113, -65, -36, 28, -47, 23, 100, 84, 26, -77, -119, 107, 57, -27, -97, -60, -93,
            -48, 78, -66, -69, 58, 103, -82, -109, 116, 89, 61, -73, -110, 31, 97, 34, -117, 26, 48, -60, -72, -118, -9,
            92, -121, -107, 19, -10, 79, 10};

    @Test
    public void testGetRSAKey() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_RSA_KEY);
        assertArrayEquals(SAMPLE_ENCODED_RSA_KEY, key.getEncoded());
    }

    @Test
    public void testRSAKeyFingerprint() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_RSA_KEY);
        assertEquals(SAMPLE_RSA_KEY_FINGERPRINT, KeyUtils.calculateFingerprint(key));
    }

    @Test
    public void testGetRSAKeyWithWhitespace() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_RSA_KEY_WITH_WHITESPACE);
        assertArrayEquals(SAMPLE_ENCODED_RSA_KEY, key.getEncoded());
    }

    @Test
    public void testRSAKeyFingerprintWithWhitespace() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_RSA_KEY_WITH_WHITESPACE);
        assertEquals(SAMPLE_RSA_KEY_FINGERPRINT, KeyUtils.calculateFingerprint(key));
    }

    @Test
    public void testGetDSAKey() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_DSA_KEY);
        assertArrayEquals(SAMPLE_ENCODED_DSA_KEY, key.getEncoded());
    }

    @Test
    public void testGetDSAKeyFingerprint() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_DSA_KEY);
        assertEquals(SAMPLE_DSA_KEY_FINGERPRINT, KeyUtils.calculateFingerprint(key));
    }

    @Test
    public void testGetECDSAKey() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_ECDSA_KEY);
        assertArrayEquals(SAMPLE_ENCODED_ECDSA_KEY, key.getEncoded());
    }

    @Test
    public void testGetECDSAKeyFingerprint() throws Exception {
        final PublicKey key = KeyUtils.getPublicKey(SAMPLE_ECDSA_KEY);
        assertEquals(SAMPLE_ECDSA_KEY_FINGERPRINT, KeyUtils.calculateFingerprint(key));
    }

    @Test
    public void getSimpleLabel() {
        assertEquals("MyLabel", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " MyLabel"));
    }

    @Test
    public void getSimpleLabelAfterWhitespaceKey() {
        assertEquals("MyLabel", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY_WITH_WHITESPACE + " MyLabel"));
    }

    @Test
    public void getEmptyLabel() {
        assertEquals("", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " "));
    }

    @Test
    public void getLabelOfOneSpace() {
        assertEquals("", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + "  "));
    }

    @Test
    public void getLabelOfTwoSpaces() {
        assertEquals("", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + "   "));
    }

    @Test
    public void getVeryShortLabel() {
        assertEquals("a", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " a"));
    }

    @Test
    public void getVeryLongLabel() {
        String veryLongLabel = new StringBuilder()
                .append("Competently pontificate B2B scenarios after just in time benefits. Interactively matrix equity ")
                .append("invested e-business through interoperable paradigms. Uniquely pursue resource-leveling ")
                .append("infrastructures without bricks-and-clicks content. Enthusiastically architect exceptional ")
                .append("technology through wireless meta-services. Dynamically strategize scalable methodologies through ")
                .append("long-term high-impact methodologies. Distinctively exploit market-driven imperatives with cross ")
                .append("functional niche markets. Synergistically conceptualize web-enabled initiatives after ")
                .append("resource-leveling opportunities. Interactively leverage existing interactive methodologies for ")
                .append("diverse sources. Energistically target high-quality paradigms through quality applications. ")
                .append("Professionally architect enabled outsourcing for user friendly expertise. Globally ")
                .append("disintermediate backend deliverables and premium deliverables. Objectively monetize 2.0 content ")
                .append("through client-centered manufactured products. Distinctively strategize premier meta-services ")
                .append("through reliable initiatives. Quickly actualize parallel architectures after multimedia based ")
                .append("solutions. Globally communicate seamless niche markets without scalable outside-the-box ")
                .append("thinking.")
                .toString();

        assertEquals(veryLongLabel, KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " " + veryLongLabel));
    }

    @Test
    public void getLabelWithPrefixedSpaces() {
        assertEquals("MyLabel", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + "  MyLabel"));
    }

    @Test
    public void getLabelWithPostfixedSpaces() {
        assertEquals("MyLabel", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " MyLabel "));
    }

    @Test
    public void getLabelWithInterstitialSpaces() {
        assertEquals("My label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " My label"));
    }

    @Test
    public void getLabelWithInterstitialSpacesAfterWhitespaceKey() {
        assertEquals("My label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY_WITH_WHITESPACE + " My label"));
    }

    @Test
    public void getLabelWithEndOfLineChars() {
        assertEquals("My label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " My\nlabel"));
    }

    @Test
    public void getLabelWithQuotes() {
        assertEquals("My\"Label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " My\"Label"));
    }

    @Test
    public void getLabelWithAccentedChars() {
        assertEquals("àáâãäåçèéêëìíîðñòôõöö", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " àáâãäåçèéêëìíîðñòôõöö"));
    }

    @Test
    public void getLabelWithAsianChars() {
        assertEquals("国際交流基金海外運営専門員", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " 国際交流基金海外運営専門員"));
    }

    @Test
    public void getLabelWithTildas() {
        assertEquals("~My~Label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " ~My~Label"));
    }

    @Test
    public void getLabelWithAtSymbols() {
        assertEquals("@My @Label@", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " @My @Label@"));
    }

    @Test
    public void getLabelWithBraces() {
        assertEquals("My()Label", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " My()Label"));
    }

    @Test
    public void getLabelWithJavaScript() {
        assertEquals("<script>alert(666)</script>", KeyUtils.getKeyComment("ssh-rsa " + SAMPLE_RSA_ENCODED_KEY + " <script>alert(666)</script>"));
    }
}
