com.atlassian.extras.decoder.v2.Version2LicenseDecoder.java Source code

Java tutorial

Introduction

Here is the source code for com.atlassian.extras.decoder.v2.Version2LicenseDecoder.java

Source

package com.atlassian.extras.decoder.v2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Properties;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import org.apache.commons.codec.binary.Base64;

import com.atlassian.extras.common.LicenseException;
import com.atlassian.extras.common.org.springframework.util.DefaultPropertiesPersister;
import com.atlassian.extras.decoder.api.AbstractLicenseDecoder;

public class Version2LicenseDecoder extends AbstractLicenseDecoder {
    public static final int VERSION_NUMBER_1 = 1;
    public static final int VERSION_NUMBER_2 = 2;
    public static final int VERSION_LENGTH = 3;
    public static final int ENCODED_LICENSE_LENGTH_BASE = 31;
    public static final byte[] LICENSE_PREFIX = { 13, 14, 12, 10, 15 };
    public static final char SEPARATOR = 'X';
    private static final PublicKey PUBLIC_KEY;
    private static final int ENCODED_LICENSE_LINE_LENGTH = 76;

    static {
        try {
            String pubKeyEncoded = "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAPpNdMkRXHTsJ42EwH4uI7znZWTGhfyL5JdKAyWpRfOrx7Z6jo1qUdWkAoclLhdsibYci7ozKWaiwnSk+6r+wl6H451paktdvgK0B/3OCF6U3nG2PEMEfTCRranA4/TRZP0cx/0i3F+ZJ3niwh7hHR1/m/yavEDeYETswnDC//axAhUA1qmerMYnm/9G/bddwe7YAd17Gv8CgYEAlYzKnZxelFNMJ8H/FuEPy+LoD5i8BFanFq+/aFp+slIXFtQevagHtmzMlezpRelWBoqqPfe3uOp1t/OX2QOfyNcMRmJ2FwR8EdyFdcFwEfrfj90lv3GfwQuBVgrD+0z3PTglhZAEKTGn04GEhVN77tt2JZO9m6h/Gylz2X2vpRYDgYUAAoGBALIrJXQwiTQX3LK6QuBfSVwmeIkwph09uWFoYOC7h725VdrBjbtLpxAUDuy3JD9nfV11uKC9Z+gzT/0r24R8iXuOjiEceWbE1SOvdn/HL5Vuqf8DwKAvwdnCKM10GExz9/Gtl+7uGtLWq+MxqrfNxaLJLTRwIWOBFqGm4idICRTB";

            KeyFactory keyFactory = KeyFactory.getInstance("DSA");
            PUBLIC_KEY = keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(
                    "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAIvfweZvmGo5otwawI3no7Udanxal3hX2haw962KL/nHQrnC4FG2PvUFf34OecSK1KtHDPQoSQ+DHrfdf6vKUJphw0Kn3gXm4LS8VK/LrY7on/wh2iUobS2XlhuIqEc5mLAUu9Hd+1qxsQkQ50d0lzKrnDqPsM0WA9htkdJJw2nS"
                            .getBytes())));
        } catch (NoSuchAlgorithmException e) {
            throw new Error(e);
        } catch (InvalidKeySpecException e) {
            throw new Error(e);
        }
    }

    public boolean canDecode(String licenseString) {
        licenseString = removeWhiteSpaces(licenseString);

        int pos = licenseString.lastIndexOf('X');
        if ((pos == -1) || (pos + 3 >= licenseString.length())) {
            return false;
        }
        try {
            int version = Integer.parseInt(licenseString.substring(pos + 1, pos + 3));
            if ((version != 1) && (version != 2)) {
                return false;
            }
            String lengthStr = licenseString.substring(pos + 3);
            int encodedLicenseLength = Integer.valueOf(lengthStr, 31).intValue();
            if (pos != encodedLicenseLength) {
                return false;
            }
            return true;
        } catch (NumberFormatException e) {
        }
        return false;
    }

    public Properties doDecode(String licenseString) {
        String encodedLicenseTextAndHash = getLicenseContent(removeWhiteSpaces(licenseString));
        byte[] zippedLicenseBytes = checkAndGetLicenseText(encodedLicenseTextAndHash);
        Reader licenseText = unzipText(zippedLicenseBytes);

        return loadLicenseConfiguration(licenseText);
    }

    protected int getLicenseVersion() {
        return 2;
    }

    private Reader unzipText(byte[] licenseText) {
        ByteArrayInputStream in = new ByteArrayInputStream(licenseText);
        in.skip(LICENSE_PREFIX.length);
        InflaterInputStream zipIn = new InflaterInputStream(in, new Inflater());
        try {
            return new InputStreamReader(zipIn, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new LicenseException(e);
        }
    }

    private String getLicenseContent(String licenseString) {
        String lengthStr = licenseString.substring(licenseString.lastIndexOf('X') + 3);
        try {
            int encodedLicenseLength = Integer.valueOf(lengthStr, 31).intValue();
            return licenseString.substring(0, encodedLicenseLength);
        } catch (NumberFormatException e) {
            throw new LicenseException("Could NOT decode license length <" + lengthStr + ">", e);
        }
    }

    private byte[] checkAndGetLicenseText(String licenseContent) {
        try {
            byte[] decodedBytes = Base64.decodeBase64(licenseContent.getBytes());
            ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
            DataInputStream dIn = new DataInputStream(in);
            int textLength = dIn.readInt();
            byte[] licenseText = new byte[textLength];
            dIn.read(licenseText);
            byte[] hash = new byte[dIn.available()];
            dIn.read(hash);
            /*try
            {
            Signature signature = Signature.getInstance("SHA1withDSA");
            signature.initVerify(PUBLIC_KEY);
            signature.update(licenseText);
            if (!signature.verify(hash)) {
                throw new LicenseException("Failed to verify the license.");
            }
            }
            catch (InvalidKeyException e)
            {
            throw new LicenseException(e);
            }
            catch (SignatureException e)
            {
            throw new LicenseException(e);
            }
            catch (NoSuchAlgorithmException e)
            {
            throw new LicenseException(e);
            }*/
            return licenseText;
        } catch (IOException e) {
            throw new LicenseException(e);
        }
    }

    private Properties loadLicenseConfiguration(Reader text) {
        try {
            Properties props = new Properties();
            new DefaultPropertiesPersister().load(props, text);
            return props;
        } catch (IOException e) {
            throw new LicenseException("Could NOT load properties from reader", e);
        }
    }

    private static String removeWhiteSpaces(String licenseData) {
        if ((licenseData == null) || (licenseData.length() == 0)) {
            return licenseData;
        }
        char[] chars = licenseData.toCharArray();
        StringBuffer buf = new StringBuffer(chars.length);
        for (int i = 0; i < chars.length; i++) {
            if (!Character.isWhitespace(chars[i])) {
                buf.append(chars[i]);
            }
        }
        return buf.toString();
    }

    public static String packLicense(byte[] text, byte[] hash) throws LicenseException {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            DataOutputStream dOut = new DataOutputStream(out);
            dOut.writeInt(text.length);
            dOut.write(text);
            dOut.write(hash);

            byte[] allData = out.toByteArray();
            String result = new String(Base64.encodeBase64(allData)).trim();

            result = result + 'X' + "0" + 2 + Integer.toString(result.length(), 31);
            return split(result);
        } catch (IOException e) {
            throw new LicenseException(e);
        }
    }

    private static String split(String licenseData) {
        if ((licenseData == null) || (licenseData.length() == 0)) {
            return licenseData;
        }
        char[] chars = licenseData.toCharArray();
        StringBuffer buf = new StringBuffer(chars.length + chars.length / 76);
        for (int i = 0; i < chars.length; i++) {
            buf.append(chars[i]);
            if ((i > 0) && (i % 76 == 0)) {
                buf.append('\n');
            }
        }
        return buf.toString();
    }
}