diff --git a/README b/README deleted file mode 100644 index bc20128cc7beb3b0a9c090f8a0d251926ed68284..0000000000000000000000000000000000000000 --- a/README +++ /dev/null @@ -1,27 +0,0 @@ -# How it work ? - - -# Usage - -## Generate your public and private key - -Create the private key (containing information to create the public key). - - $ openssl genrsa -out privkey.pem 2048 - $ openssl pkcs8 -topk8 -in privkey.pem -inform PEM -nocrypt -outform DER -out privkey.der - -Extract the public key, for publishing. - $ openssl rsa -in privkey.pem -out pubkey.der -pubout -outform DER - - - -# License - -This program is free software; you can redistribute it and/or modify -it under the terms of Apache License 2.0 - -You should have received a copy of the Apache License 2.0 -along with this program in the file named "LICENSE". - -This package is based on the following article: -http://blog.afewguyscoding.com/2012/02/licensing-module-java/ diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..89503ea3f82055f8e49716721220f03dbda502b0 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# How it work ? +This project provide a java library to be used by your java project to easily validate a license file. + +1. You generate a private and public key. +2. You publish your application with this library and your public key. +3. You keep the private key for youself. + +1. You generate a license file for your user with a deadline. +2. You are sending this file to your user (via email or similar). +3. Your user install this license file where your application can pick it up. +4. When your application start, this library is used to validate the license file and validate the deadline. + +# Usage + +## Generate your public and private key + +Create the private key: + + openssl genrsa -out privkey.pem 2048 + openssl pkcs8 -topk8 -in privkey.pem -inform PEM -nocrypt -outform DER -out privkey.der + +Extract the public key, for publishing: + + openssl rsa -in privkey.pem -out pubkey.der -pubout -outform DER + +## Publish your application with this library +To make use of this license library, you must change a bit the implementation of your application. First, you must import the library. For maven project, you may edit the `pom.xml` as follow: + + + + patrikdufresne + http://nexus.patrikdufresne.com/content/groups/public/ + + + + ... + + + + com.patrikdufresne + license + 0.11 + + + + +In your java code, you must implement something similar. + + License l; + try { + l = LicenseManager.validate(Main.class.getResourceAsStream("/pubkey.der"), new File("application.lic")); + } catch (LicenseException e) { + System.out.println("invalid license file:" + e.getMessage()); + System.exit(1); + return; + } + System.out.println("License to: " + l.getProperty(License.NAME)); + System.out.println("Expired: " + l.getProperty(License.EXPIRATION)); + +Take a loot at http://git.patrikdufresne.com/pdsl/license/blob/master/docs/examples/Main.java + +## Generate a license file + +To generate a license file you may use the jar it self in command line: + + wget https://nexus.patrikdufresne.com/repository/public/com/patrikdufresne/license/0.11/license-0.11.jar + java -jar license-0.11.jar create -p pubkey.der -P privkey.der -n username -m test@example.com -e 2020-01-09 + +It's generate a license file named `application.lic`. + + +# Notes +This library is compatible with Java 7 and earlier. This library doesn't need any dependecies. + diff --git a/docs/examples/Main.java b/docs/examples/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..d5ef3e02edae627b2e23f184f96de7f2bde06f05 --- /dev/null +++ b/docs/examples/Main.java @@ -0,0 +1,41 @@ +/** + * Copyright(C) 2013 Patrik Dufresne Service Logiciel + * + * 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 net.ekwos; + +import java.io.File; + +import com.patrikdufresne.license.License; +import com.patrikdufresne.license.LicenseException; +import com.patrikdufresne.license.LicenseManager; + +public class Main { + + public static void main(String[] args) { + + License l; + try { + l = LicenseManager.validate(Main.class.getResourceAsStream("/pubkey.der"), new File("application.lic")); + } catch (LicenseException e) { + System.out.println("invalid license file:" + e.getMessage()); + System.exit(1); + return; + } + System.out.println("License to: " + l.getProperty(License.NAME)); + System.out.println("Expired: " + l.getProperty(License.EXPIRATION)); + + } + +} diff --git a/docs/examples/application.lic b/docs/examples/application.lic new file mode 100644 index 0000000000000000000000000000000000000000..a92afc7002dff6dec8d1e044bbf65cf31424ed6d --- /dev/null +++ b/docs/examples/application.lic @@ -0,0 +1,7 @@ +#License file +#Wed Jan 16 16:00:25 EST 2019 +signature=JLGa91NTwe4KBppK+dmy7JIor9QdW+frG8Zmun5i57b3b1jgeeNDtGibxM1poMdPPg4lyoP6R8qCQwSbfzE/DV7uj+awNzHesAxMohOfGI7rc7RH91o9OUzx8r1iuObJnOhhDOnxVmFrBdKxxYXopl1gqdF9B+wGzv7pyHp9hG3ayTId0NG6zISlX1RWDVqeVnXQoarVSa6Xmc7fBSW1XswFtyLCuJO932IS73V6Det0Y+3xAwvZRShouMSL5NOUyCZcwVCsvghY24x5BJYd7PmYOTEwuwW1uCEzRAu64G0a/Ysh/5/ciVc2FyNPOmODvf4P02FW6z6hL4sEfLcwyQ\=\= +licenseType=trial +expiration=2020-01-01 +email=info@patrikdufresne.com +name=patrik diff --git a/docs/examples/privkey.der b/docs/examples/privkey.der new file mode 100644 index 0000000000000000000000000000000000000000..e2783a2d8d375804835860b3c91be1fad5479558 Binary files /dev/null and b/docs/examples/privkey.der differ diff --git a/docs/examples/privkey.pem b/docs/examples/privkey.pem new file mode 100644 index 0000000000000000000000000000000000000000..2de9fb3aba6b8acd5606611058c357c004b23014 --- /dev/null +++ b/docs/examples/privkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA2aUh7+dLXmrQqtTXOdZu9MktrAlG9x1Oo2xEVXD9lEuEGnP6 +VGCuE9Kib+945b8lSBgKgCrT0R3wajUDLH/3YzoX6O0B5kRrp7DlaCH6mUTmfpTv +XvIfhIXamozfLRG6Rg0gGL7JMwspJYnct1dB4H9piCEM2jE2pDpLOUKEgvCz3yPW +IF8aolLXs+P+0Ael3gpqGfIRtuHbTd8PTcTfEHhWc55D50qdptv2y624kKxU9mqY +FHhTFBRbuFPKF80xAXzSmNhx+MIRzLZfhCxIj1HN7cJcQDCdDuisKJmn/nLWTsXd +vmvM8FP8x8DKehukwibvx2AKb7xrE119+uU8JQIDAQABAoIBAAOR7NuVjKvwzplu +wlUFim5jemdPA6X8ChUuKnTIVLCBCJqyelG2AET8+IMjh3UlTIRBOLLfgPf2KMJl +OjcZpkIvasL8WEKhrq5ifXDW1dh7w9ghs0d4a0HuPCa61tJTbx3FC1i8kGpQ7Yzb +FQ7A1KjNDjsYZ7CQjBfniOJYj/nh1yLycoPjNFjIp6kGn5t1yTk48iv5JPzJe/lE +kZVC6BVt4oUc4W2bFsVxg0jXqFvM+nazbUFGFDV/rr3YxNILdBxCPVF5JtUyaqBj +RMWgaWVEzgJjT9eKZwAE13SFufnyiI1UZquwi+2QQqdEbrB9cmq81GTnMURKj57g +YVJ5GcECgYEA7rfH/KZ5iMFePYaH/g7Q7T7YemAzRDsQQ/hW7bd1I7YWmNqXOeJJ +fycgTJaXJqD3X7658pHjp1gpUfemkBXIMIO4bcGgS3P10r0L890PGR6ZqdIYVoHn +UuPc56junMO1/Ansz3HpUOlZV0iAdHgJ4YQvnT3SoaE56ndUSjUBNJECgYEA6WbN +kfReAzxmkLpFOppNqG0lOJ2Rzbz05IzjnL7qrbL6KXm8X2VT5uK7QN13ceqgLUG3 +zRzQziBwVsim4EYP612I9bKsDTFjvsAm7fCnxvkgJEzh7jPeeXUlIrcchIUna5EQ +TdxLU8FlwfK6gwjxZdjvq6pGpDnzo7/+rUJWSFUCgYEA44rwqMXyUMWo09KZbDSp +N4tRA40RMPdvsKpWCe92S9z0Oy0ZOwaUcgxUgEyGtT53rZ76Vdpz+n5RnJ0H+o2Y +rY3QzWXkKifVaNPkQcYz7wi5BiOKKWNXoS4r0fG3yFvQ6vZ28OGuuP5Et6sXLm2B +VaIPVL2qOYCZ2QF3qehORtECgYEAgp+8UQEYVGtLY5g8Am41JBvhhuv4m9IypG6N +PD5FDO1rwCaXXDRTXpZqAgVwQdrzxiBPg4Wq/pF9DbTCYCYV5r20Vv2l+MQ5dJoJ +r4TOATeP24EDuNJioksDe4hLd4cl5reLDmhJ6BgGoSL9azRoFX3xtHtZibO9PVnI +aKMFsvkCgYBuyxlbngBYAGLm62T1sQqaEzNLGVZKx7S7kNIr6aTpi9DRReOjlHgP +Xb/f9ckxDcTgk9JFg5dkQMWlZhhLVqxtpiCU9cHjLHMfCWB8cs86fvbGeqTr0L80 +HcVvnC5W3vlQ90eb5WjNx9l9WeOklS4qrNkCJt931bl3P7CH39Fc5Q== +-----END RSA PRIVATE KEY----- diff --git a/docs/examples/pubkey.der b/docs/examples/pubkey.der new file mode 100644 index 0000000000000000000000000000000000000000..61461d9e122d6e58f725d2c5c7dff449c7446dfb Binary files /dev/null and b/docs/examples/pubkey.der differ diff --git a/pom.xml b/pom.xml index 03959660febf9622addd523ce78d327a341d6239..cc64b4c6696e121b80af8435e78057b3f32d49cb 100644 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,18 @@ false + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.patrikdufresne.license.Main + + + + diff --git a/src/main/java/com/patrikdufresne/license/Main.java b/src/main/java/com/patrikdufresne/license/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..d70ccd1e97168629e394632ecad1de34a4da346e --- /dev/null +++ b/src/main/java/com/patrikdufresne/license/Main.java @@ -0,0 +1,159 @@ +/** + * Copyright(C) 2018 Patrik Dufresne Service Logiciel + * + * 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.patrikdufresne.license; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Main entry point when this library is executed from command line. + * + * @author Patrik Dufresne + * + */ +public class Main { + + public static void create(String publicKey, String privateKey, String name, String email, String expiration, String output) + throws GeneralSecurityException, + IOException { + if (publicKey == null) { + throw new IllegalArgumentException("public key is missing"); + } + if (privateKey == null) { + throw new IllegalArgumentException("private key is missing"); + } + if (expiration == null) { + throw new IllegalArgumentException("expiration date is missing"); + } + + // Create license obj + License license = new License(); + license.setProperty(License.NAME, name); + license.setProperty(License.EMAIL, email); + license.setProperty(License.LICENSE_TYPE, License.TYPE_TRIAL); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date d; + try { + d = dateFormat.parse(expiration); + } catch (ParseException e1) { + throw new IllegalArgumentException("Wrong date value: " + expiration); + } + license.setExpiration(d); + + // Create the license file + LicenseManager manager = new LicenseManager(publicKey, privateKey); + manager.writeLicense(license, new File(output)); + + } + + public static void main(String[] args) throws GeneralSecurityException { + if (args.length == 0) { + usage(); + return; + } + // Parse arguments + String publicKey = null; + String privateKey = null; + String name = ""; + String email = ""; + String expiration = null; + String file = "application.lic"; + + String action = args[0]; + if (!action.equals("create") && !action.equals("validate")) { + usage(); + return; + } + int idx = 1; + while (idx < args.length) { + switch (args[idx]) { + case "-p": + case "--public": + idx++; + publicKey = args[idx]; + break; + case "-P": + case "--private": + idx++; + privateKey = args[idx]; + break; + case "-n": + case "--name": + idx++; + name = args[idx]; + break; + case "-m": + case "--email": + idx++; + email = args[idx]; + break; + case "-e": + case "--expiration": + idx++; + expiration = args[idx]; + break; + case "-f": + case "--file": + idx++; + file = args[idx]; + break; + default: + System.err.println("unknown arguments: " + args[idx]); + usage(); + return; + } + idx++; + } + // Take action. + try { + if (action.equals("create")) { + create(publicKey, privateKey, name, email, expiration, file); + System.out.println("license " + file + " created"); + } else if (action.equals("validate")) { + try { + LicenseManager.validate(new FileInputStream(publicKey), new File(file)); + } catch (LicenseException e) { + System.out.println("license " + file + " invalid: " + e.getMessage()); + System.exit(1); + } + System.out.println("license " + file + " valid"); + } else { + usage(); + } + } catch (IOException | IllegalArgumentException e) { + System.err.println(e.getMessage()); + System.exit(1); + } + + } + + public static void usage() { + System.out.println("usage:"); + System.out.println(" create -p pubkey.der -P privkey.der [-n name] [-m email] -e YYYY-mm-dd [-f application.lic]"); + System.out.println(" validate -p pubkey.der [-f application.lic]"); + System.out.println(""); + System.out.println(" -p, --public define the public key file in DER format"); + System.out.println(" -P, --private define the private key file file in DER format"); + System.out.println(" -n, --name name to be stored in the license file (optional)"); + System.out.println(" -m, --mail email to be stored in the license file (optional)"); + System.out.println(" -e, --expiration expiration date in YYYY-mm-dd format"); + System.out.println(" -f, --file the license file to be created or validated (default: application.lic)"); + System.exit(1); + } + +}