/**
 *
 * @name node-sodium
 * @author bmf
 * @date 11/11/13
 * @version  $
 */
var assert = require('assert');
var sodium = require('../lib/sodium');

describe("Box", function () {
    it("Example of sending an encrypted message ", function (done) {

        // Generate random keys for alice and bob
        var alice = new sodium.Key.Box();
        var bob = new sodium.Key.Box();

        // Create a signature Alice's side using her secret key and Bob's public key
        var aliceBox = new sodium.Box(bob.pk(), alice.sk());
        var cipherText = aliceBox.encrypt("super secret message",
            "utf8");

        // Alice sends message to Bob, and he decrypts it

        var bobBox = new sodium.Box(alice.pk(), bob.sk());
        var plainText = aliceBox.decrypt(cipherText, "utf8");

        assert.equal(plainText, 'super secret message');
        done();
    });
});

describe("Sign", function () {
    it("Example of signing a message ", function (done) {

        // Alice's side
        // Generate random signing keys for alice
        var aliceKey = new sodium.Key.Sign();

        // Alice signs the message
        var aliceSign = new sodium.Sign(aliceKey);
        var signature = aliceSign.sign("important signed message",
            "utf8");

        // Alice sends signed message to bob

        // Bob's side
        // Bob receives signature and tries to verify it.
        // As the var signature includes Alice's public key Bob can simply call verify
        // Please note that in this simple form Bob can only be sure that the message
        // was signed with the secret key that is paired with the public key inside
        // signature. Bob cannot be certain that the public key is indeed Alice's public key
        // Using public keys directly, ie, without a digital certificate is open to
        // impersonation using 'man-in-the-middle' attacks.
        var bobMsg = new sodium.Sign.verify(signature);
        assert.ok(bobMsg);

        // Bob checks the message extracted from the signature
        assert.equal(bobMsg.toString('utf8'), 'important signed message');
        done();
    });
});

describe("Auth", function () {
    it("Using authentication tokens ", function (done) {
        /**
         * User Side
         *
         * The user will use its key ID and secret key to authenticate a message that she
         * is sending to the server.
         * The Key ID allows the server to later retrieve the secret key from its database
         */
        var restKeyID = '123123';
        var restAPIKey =
            'afcd09812fe556aac311de3faade13afcd09812fe556aac311de3faade13ade3';

        // User's request to the server
        var request = 'http://api.example.domain/query?keyid=' +
            restKeyID;

        // Create authentication object
        var auth = new sodium.Auth(restAPIKey);

        // Generate authentication token for the request
        var authToken = auth.generate(request, 'utf8');

        // Append the authToken to the request
        var token = authToken.toString('base64');
        request += "&token=" + token;

        // Send request to server.

        /**
         * Server Side
         *
         * HTTP Server processes the query string and extracts the token and key Id
         * To keep the example simple we just reuse the token, restAPIKey and restKeyId
         * variables.
         *
         * After extracting the token and key ID from the query string the server can
         * retrieve the corresponding secret key from a database, and use it to validate
         * the authentication token.
         */
        var serverAuth = new sodium.Auth(restAPIKey);

        // In this simulation we just recreate the original query before token was appended
        request = 'http://api.example.domain/query?keyid=' + restKeyID;

        // Convert the token to a buffer
        var tBuffer = sodium.Utils.toBuffer(token, 'base64');

        /**
         * If validate returns true then the token could only have been generated by
         * the user that has the same secret key as identified by key Id.
         * The keys and key Ids are usually generated by an administrator when the user
         * signs up for the service.
         */
        assert.ok(serverAuth.validate(tBuffer, request, 'utf8'));
        done();
    });
});

describe("OneTimeAuth", function () {
    it("Using one time authentication tokens ", function (done) {
        /**
         * User Side
         *
         * The user will use its key ID and secret key to authenticate a message that she
         * is sending to the server.
         * The Key ID allows the server to later retrieve the secret key from its database
         *
         * As the name implies this authentication scheme should only be used one time,
         * for one message, using the same key. So you should change keys after each
         * message.
         */
        var restKeyID = '123123';
        var restAPIKey =
            'afcd09812fe556aac311de3faade13afcd09812fe556aac311de3faade13ade3';

        // User's request to the server
        var request = 'http://api.example.domain/query?keyid=' +
            restKeyID;

        // Create authentication object
        var auth = new sodium.OneTimeAuth(restAPIKey);

        // Generate authentication token for the request
        var authToken = auth.generate(request, 'utf8');

        // Append the authToken to the request
        var token = authToken.toString('base64');
        request += "&token=" + token;

        // Send request to server.

        /**
         * Server Side
         *
         * HTTP Server processes the query string and extracts the token and key Id
         * To keep the example simple we just reuse the token, restAPIKey and restKeyId
         * variables.
         *
         * After extracting the token and key ID from the query string the server can
         * retrieve the corresponding secret key from a database, and use it to validate
         * the authentication token.
         */
        var serverAuth = new sodium.OneTimeAuth(restAPIKey);

        // In this simulation we just recreate the original query before token was appended
        request = 'http://api.example.domain/query?keyid=' + restKeyID;

        // Convert the token to a buffer
        var tBuffer = sodium.Utils.toBuffer(token, 'base64');

        /**
         * If validate returns true then the token could only have been generated by
         * the user that has the same secret key as identified by key Id.
         * The keys and key Ids are usually generated by an administrator when the user
         * signs up for the service.
         */
        assert.ok(serverAuth.validate(tBuffer, request, 'utf8'));
        done();
    });
});

describe("SecretBox", function () {
    it("Example of sending an encrypted message ", function (done) {

        // Alice and Bob both agree on a secret key that they have
        // shared in some secure way

        // Alice's Side
        var aliceKey = Buffer.from("fcd09812fe556aac311de3faade13afa");
        var aliceBox = new sodium.SecretBox(aliceKey);

        // Create a signature Alice's side using her secret key and Bob's public key
        var cipherText = aliceBox.encrypt("super secret message",
            "utf8");

        // Alice sends message to Bob, and he decrypts it

        // Bob's Side
        // Bob uses the same scret key as Alice
        var bobKey = Buffer.from("fcd09812fe556aac311de3faade13afa");
        var bobBox = new sodium.SecretBox(bobKey);

        var plainText = bobBox.decrypt(cipherText, "utf8");

        assert.equal(plainText, 'super secret message');
        done();
    });
});

describe("ECDH", function () {
    it("should calculate the same secret", function (done) {
        var bob = new sodium.Key.ECDH();
        var alice = new sodium.Key.ECDH();

        var aliceDH = new sodium.ECDH(bob.pk(), alice.sk());
        var bobDH = new sodium.ECDH(alice.pk(), bob.sk());

        var bobSecret = bobDH.secret();
        var aliceSecret = aliceDH.secret();

        assert.deepEqual(bobSecret, aliceSecret);
        done();
    });

    it("should calculate the same session key", function (done) {
        var bob = new sodium.Key.ECDH();
        var alice = new sodium.Key.ECDH();

        var aliceDH = new sodium.ECDH(bob.pk().get(), alice.sk().get());
        var bobDH = new sodium.ECDH(alice.pk().get(), bob.sk().get());

        var bobSecret = bobDH.sessionKey();
        var aliceSecret = aliceDH.sessionKey();

        assert.deepEqual(bobSecret, aliceSecret);
        done();
    });
});
