com.google.nigori.common.MessageLibrary.java Source code

Java tutorial

Introduction

Here is the source code for com.google.nigori.common.MessageLibrary.java

Source

/*
 * Copyright (C) 2011 Alastair R. Beresford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.nigori.common;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import com.google.nigori.common.NigoriMessages.AuthenticateRequest;
import com.google.nigori.common.NigoriMessages.DeleteRequest;
import com.google.nigori.common.NigoriMessages.GetIndicesRequest;
import com.google.nigori.common.NigoriMessages.GetIndicesResponse;
import com.google.nigori.common.NigoriMessages.GetRequest;
import com.google.nigori.common.NigoriMessages.GetResponse;
import com.google.nigori.common.NigoriMessages.GetRevisionsRequest;
import com.google.nigori.common.NigoriMessages.GetRevisionsResponse;
import com.google.nigori.common.NigoriMessages.PutRequest;
import com.google.nigori.common.NigoriMessages.RegisterRequest;
import com.google.nigori.common.NigoriMessages.RevisionValue;
import com.google.nigori.common.NigoriMessages.UnregisterRequest;
import com.google.protobuf.ByteString;
import com.google.protobuf.GeneratedMessage;

public class MessageLibrary {

    private static final boolean DEBUG = false;

    //The character set used to encode all string-based communications in Nigori.
    public static final String CHARSET = "UTF-8";

    public static byte[] toBytes(String string) {
        try {
            return string.getBytes(CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);// never happens as UTF-8 is supported
        }
    }

    public static String bytesToString(byte[] bytes) {
        try {
            return new String(bytes, CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);// never happens as UTF-8 is supported
        }
    }

    //The mimetypes used for all supported communication formats in Nigori
    public static final String MIMETYPE_JSON = "application/json";
    public static final String MIMETYPE_PROTOBUF = "application/x-google-protobuf";

    public static final String REQUEST_GET = "get";
    public static final String REQUEST_GET_INDICES = "get-indices";
    public static final String REQUEST_GET_REVISIONS = "get-revisions";
    public static final String REQUEST_PUT = "put";
    public static final String REQUEST_DELETE = "delete";
    //public static final String REQUEST_UPDATE = "update";
    public static final String REQUEST_AUTHENTICATE = "authenticate";
    public static final String REQUEST_REGISTER = "register";
    public static final String REQUEST_UNREGISTER = "unregister";

    private static Gson gson = initializeGson();

    private static Gson initializeGson() {

        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(GetRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(GetResponse.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(GetIndicesRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(GetIndicesResponse.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(GetRevisionsRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(GetRevisionsResponse.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(PutRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(DeleteRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(RegisterRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(UnregisterRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(AuthenticateRequest.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(RevisionValue.class, new TypeAdapterProtobuf());
        gsonBuilder.registerTypeAdapter(ByteString.class, new TypeAdapterByteString());
        gsonBuilder.setPrettyPrinting();
        return gsonBuilder.create();
    }

    @SuppressWarnings("serial")
    public static class JsonConversionException extends Exception {
        JsonConversionException(String msg) {
            super(msg);
        }
    }

    public static String toJson(GeneratedMessage src) {
        return gson.toJson(src);
    }

    private static <T extends GeneratedMessage> T fromJson(String json, Class<T> clz)
            throws JsonConversionException {
        try {
            return gson.fromJson(json, clz);
        } catch (JsonSyntaxException jse) {
            throw new JsonConversionException("Invalid JSON syntax" + (DEBUG ? json : ""));
        } catch (JsonParseException jse) {
            throw new JsonConversionException(
                    "Unable to parse JSON fields into correct message format" + (DEBUG ? json : ""));
        }
    }

    public static GetRequest getRequestAsProtobuf(String serverName, DSASign signer, byte[] index, byte[] revision)
            throws NigoriCryptographyException {

        if (revision != null) {
            return GetRequest.newBuilder()
                    .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_GET, index, revision))
                    .setKey(ByteString.copyFrom(index)).setRevision(ByteString.copyFrom(revision)).build();
        } else {
            return GetRequest.newBuilder()
                    .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_GET, index))
                    .setKey(ByteString.copyFrom(index)).build();
        }

    }

    public static String getRequestAsJson(String serverName, DSASign signer, byte[] index, byte[] revision)
            throws NigoriCryptographyException {
        return gson.toJson(getRequestAsProtobuf(serverName, signer, index, revision));
    }

    public static GetRequest getRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetRequest.class);
    }

    public static GetResponse getResponseAsProtobuf(Collection<RevValue> revisions) {
        // TODO(drt24) add index
        List<RevisionValue> protoRevisions = new ArrayList<RevisionValue>(revisions.size());
        for (RevValue rv : revisions) {
            protoRevisions
                    .add(RevisionValue.newBuilder().setRevision(ByteString.copyFrom(rv.getRevision().getBytes()))
                            .setValue(ByteString.copyFrom(rv.getValue())).build());
        }
        GetResponse resp = GetResponse.newBuilder().addAllRevisions(protoRevisions).build();

        return resp;
    }

    public static String getResponseAsJson(Collection<RevValue> revisions) {
        return gson.toJson(getResponseAsProtobuf(revisions));
    }

    public static GetResponse getResponseFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetResponse.class);
    }

    public static GetIndicesRequest getIndicesRequestAsProtobuf(String serverName, DSASign signer)
            throws NigoriCryptographyException {
        return GetIndicesRequest.newBuilder()
                .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_GET_INDICES)).build();
    }

    public static String getIndicesRequestAsJson(String serverName, DSASign signer)
            throws NigoriCryptographyException {
        return gson.toJson(getIndicesRequestAsProtobuf(serverName, signer));
    }

    public static GetIndicesRequest getIndicesRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetIndicesRequest.class);
    }

    public static GetIndicesResponse getIndicesResponseAsProtobuf(Collection<byte[]> value) {
        List<ByteString> values = new ArrayList<ByteString>(value.size());
        for (byte[] valueA : value) {
            values.add(ByteString.copyFrom(valueA));
        }
        return GetIndicesResponse.newBuilder().addAllIndices(values).build();
    }

    public static String getIndicesResponseAsJson(Collection<byte[]> value) {
        return gson.toJson(getIndicesResponseAsProtobuf(value));
    }

    public static GetIndicesResponse getIndicesResponseFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetIndicesResponse.class);
    }

    public static GetRevisionsRequest getRevisionsRequestAsProtobuf(String serverName, DSASign signer, byte[] index)
            throws NigoriCryptographyException {
        return GetRevisionsRequest.newBuilder()
                .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_GET_REVISIONS, index))
                .setKey(ByteString.copyFrom(index)).build();
    }

    public static String getRevisionsRequestAsJson(String serverName, DSASign signer, byte[] encIndex)
            throws NigoriCryptographyException {
        return gson.toJson(getRevisionsRequestAsProtobuf(serverName, signer, encIndex));
    }

    public static GetRevisionsRequest getRevisionsRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetRevisionsRequest.class);
    }

    public static GetRevisionsResponse getRevisionsResponseAsProtobuf(Collection<byte[]> value) {
        List<ByteString> values = new ArrayList<ByteString>(value.size());
        for (byte[] valueA : value) {
            values.add(ByteString.copyFrom(valueA));
        }
        return GetRevisionsResponse.newBuilder().addAllRevisions(values).build();
    }

    public static String getRevisionsResponseAsJson(Collection<byte[]> value) {
        return gson.toJson(getRevisionsResponseAsProtobuf(value));
    }

    public static GetRevisionsResponse getRevisionsResponseFromJson(String json) throws JsonConversionException {
        return fromJson(json, GetRevisionsResponse.class);
    }

    public static PutRequest putRequestAsProtobuf(String serverName, DSASign signer, byte[] index, byte[] revision,
            byte[] value) throws NigoriCryptographyException {

        PutRequest.Builder reqBuilder = PutRequest.newBuilder()
                .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_PUT, index, revision, value))
                .setKey(ByteString.copyFrom(index)).setRevision(ByteString.copyFrom(revision))
                .setValue(ByteString.copyFrom(value));

        PutRequest req = reqBuilder.build();

        return req;
    }

    public static String putRequestAsJson(String serverName, DSASign signer, byte[] index, byte[] revision,
            byte[] value) throws NigoriCryptographyException {
        return gson.toJson(putRequestAsProtobuf(serverName, signer, index, revision, value));
    }

    public static PutRequest putRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, PutRequest.class);
    }

    public static DeleteRequest deleteRequestAsProtobuf(String serverName, DSASign signer, byte[] index)
            throws NigoriCryptographyException {
        DeleteRequest.Builder delBuilder = DeleteRequest.newBuilder()
                .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_DELETE, index))
                .setKey(ByteString.copyFrom(index));

        DeleteRequest del = delBuilder.build();

        return del;
    }

    public static String deleteRequestAsJson(String serverName, DSASign signer, byte[] index)
            throws NigoriCryptographyException {
        return gson.toJson(deleteRequestAsProtobuf(serverName, signer, index));
    }

    public static DeleteRequest deleteRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, DeleteRequest.class);
    }

    public static AuthenticateRequest authenticateRequestAsProtobuf(String serverName, DSASign signer)
            throws NigoriCryptographyException {
        return authenticateRequestAsProtobuf(serverName, signer, REQUEST_AUTHENTICATE);
    }

    protected static AuthenticateRequest authenticateRequestAsProtobuf(String serverName, DSASign signer,
            String command, byte[]... payload) throws NigoriCryptographyException {

        try {
            Nonce nonce = new Nonce();
            DSASignature signedNonce = signer.sign(Util.joinBytes(MessageLibrary.toBytes(serverName), nonce.nt(),
                    nonce.nr(), toBytes(command), Util.joinBytes(payload)));
            byte[] sig = Util.joinBytes(signedNonce.getR(), signedNonce.getS());

            AuthenticateRequest req = AuthenticateRequest.newBuilder()
                    .setPublicKey(ByteString.copyFrom(signer.getPublicHash())).setSig(ByteString.copyFrom(sig))
                    .setNonce(ByteString.copyFrom(nonce.toToken())).setServerName(serverName).build();

            return req;
        } catch (NoSuchAlgorithmException e) {
            throw new NigoriCryptographyException("Platform does have required crypto support:" + e.getMessage());
        }
    }

    public static String authenticateRequestAsJson(String serverName, DSASign signer)
            throws NigoriCryptographyException {
        return gson.toJson(authenticateRequestAsProtobuf(serverName, signer));
    }

    public static AuthenticateRequest authenticateRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, AuthenticateRequest.class);
    }

    public static RegisterRequest registerRequestAsProtobuf(DSASign signer, byte[] token) {

        RegisterRequest req = RegisterRequest.newBuilder().setPublicKey(ByteString.copyFrom(signer.getPublicKey()))
                .setToken(ByteString.copyFrom(token)).build();

        return req;
    }

    public static String registerRequestAsJson(DSASign signer, byte[] token) {
        return gson.toJson(registerRequestAsProtobuf(signer, token));
    }

    public static RegisterRequest registerRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, RegisterRequest.class);
    }

    public static UnregisterRequest unregisterRequestAsProtobuf(String serverName, DSASign signer)
            throws NigoriCryptographyException {

        UnregisterRequest req = UnregisterRequest.newBuilder()
                .setAuth(authenticateRequestAsProtobuf(serverName, signer, REQUEST_UNREGISTER)).build();

        return req;
    }

    public static String unregisterRequestAsJson(String serverName, DSASign signer)
            throws NigoriCryptographyException {
        return gson.toJson(unregisterRequestAsProtobuf(serverName, signer));
    }

    public static UnregisterRequest unregisterRequestFromJson(String json) throws JsonConversionException {
        return fromJson(json, UnregisterRequest.class);
    }
}