├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── deployment.xml ├── encodings.xml ├── google-java-format.xml ├── gradle.xml ├── hotswap_agent.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── build.gradle.kts ├── envasCommons └── envasCommons-rt │ ├── envasCommons-rt.gradle.kts │ ├── module-include.xml │ ├── module-permissions.xml │ └── src │ ├── main │ └── java │ │ └── com │ │ └── neopsis │ │ └── envas │ │ ├── commons │ │ └── license │ │ │ ├── NvAbstractLicense.java │ │ │ ├── NvLicense.java │ │ │ ├── NvLicenseFeature.java │ │ │ ├── NvLicenseLocalManager.java │ │ │ ├── NvLicenseManager.java │ │ │ └── util │ │ │ ├── ByteHex.java │ │ │ ├── JulianDateCodec.java │ │ │ └── LicenseUtils.java │ │ └── util │ │ └── NvLog.java │ └── test │ └── java │ └── com │ └── neopsis │ └── envas │ └── test │ ├── TestRunner.java │ └── Tests.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .gradle 3 | Win-0000-1234-ABCD-FFFF.l4e 4 | build 5 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | workspace.xml -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | envasCommons -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deployment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/google-java-format.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/hotswap_agent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Neopsis GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at following link. 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Envas Commons 2 | 3 | Envas commons is a [Niagara](http://www.tridium.com) module containing useful utilities 4 | for Niagara development. While developing our [Envas](http://www.envas.com) framework, 5 | we've found that we need tools that Niagara framework can not offer us. 6 | Envas commons packs some usefull open source projects and a lot of our Java code 7 | into a free Niagara module. Envas commons is licensed under Apache 2.0 license. 8 | 9 | You can download the compiled and with Neopsis certificate signed module `envasCommons-rt.jar` 10 | from [project release menu](https://github.com/neopsis/envas-commons/releases). 11 | 12 | #### Message Bus 13 | 14 | In Niagara you can subscribe for events on BComponent slots. Unfortunately, there is no 15 | way to pass events between other types of objects. Another limitation is the impossibility 16 | to send asynchronous events. The solution is the **message bus** from 17 | the envas commons module. Message bus can pass events between any Java POJO objects, the 18 | publishers and subscribers do not have to be Baja objects! The message bus is based on 19 | the great open source bus implementation [MBassador](https://github.com/bennidi/mbassador). 20 | MBassador is a light-weight, high-performance event bus implementing the publish 21 | subscribe pattern. See the Github project pages for more details about MBassador. 22 | 23 | 24 | #### Modern JSON Library 25 | 26 | Although Niagara contains **JSON utilities**, we are missing a lot of features implemented 27 | today in all modern JSON handling libraries. We found an open source project 28 | [Fastjson](https://github.com/alibaba/fastjson) matching all our needs. Fastjson is 29 | a Java library that can be used to convert Java Objects into their JSON representation. 30 | It can also be used to convert a JSON string to an equivalent Java object. Fastjson can 31 | work with arbitrary Java objects including pre-existing objects that you do not have 32 | source-code of. 33 | 34 | Fast JSON 35 | 36 | * Provides simple toJSONString() and parseObject() methods to convert Java objects to 37 | JSON and vice-versa 38 | * Allows pre-existing unmodifiable objects to be converted to and from JSON 39 | * Supports Java Generics 40 | * Allows custom representations for objects 41 | * Support arbitrarily complex objects (with deep inheritance hierarchies and extensive 42 | use of generic types) 43 | * Has much smaller size compared to similar libraries like Jackson or Gson. 44 | 45 | #### Licensing utilities 46 | 47 | If you are going to issue a license for your Niagara custom module, you can use Niagara 48 | License Server to maintain your licenses. Unfortunately, Tridium does not offer any kind of 49 | automation when creating a license. To enter a license you need to do everything by hand, 50 | with lot of data entries and copy&paste work. It's time consuming and error-prone. That's 51 | why we developed our own licensing. Envas licensing uses PKI infrastructure and implements 52 | the code for creating, signing and validation of Envas licenses. Licenses are issued 53 | as text files in the JSON format. It is up to you how you generate and deploy the licenses. 54 | You can, for example, integrate the Envas licensing into your back office workflow - a customer 55 | buys your driver on your web site, on the payment callback you will generate a license 56 | that will be automatically sent to the customer or placed on your licensing server. 57 | 58 | 59 | Envas licensing utilities implement Baja interfaces and are compatible with the original 60 | Niagara framework. If you wish to move away from Tridium licensing to Envas licensing, 61 | you need to change only one row of your code obtaining the license manager. Check the test 62 | project code for more details how to use the utility. Example of a feature check in Niagara: 63 | 64 | ``` 65 | try { 66 | Feature feature = NvLicenseLocalManager.make().getFeature("neopsis", "envas"); 67 | 68 | feature.check(); 69 | feature.getb("charts", false); 70 | ... 71 | 72 | } catch (FeatureLicenseExpiredException e) { 73 | NvLog.error("Unlicensed: neopsis:envas license expired"); 74 | 75 | } catch (FeatureNotLicensedException e) { 76 | NvLog.error("Unlicensed: neopsis:envas no license found"); 77 | 78 | } catch (LicenseDatabaseException e) { 79 | ... 80 | } 81 | ``` 82 | 83 | #### Module signing 84 | 85 | Starting from Niagara 4.7 Tridium requires module signing when using reflection. Because both utilities, 86 | Message Bus and JSON, are using reflection, you have to sign the module. 87 | 88 | Tridium uses a keystore for storing the keys and the signing certificates. The keystore location is 89 | `%user_home%\.tridium\security\_signing.jks`. The keystore password and primary key passwords of 90 | all keystone entries are stored in the profile file `%user_home%\.tridium\security\_signing.xml`. 91 | If the keystore and the XML profile do not exist, they will be created for you when the jar task runs 92 | for the first time and will be filled with the random generated values. You can use the 93 | [Keystore Explorer](https://keystore-explorer.org) for the keystore entry review. 94 | 95 | For production sites, the usage of the certificates signed by a Certification Authority is highly adviced. 96 | Using the cheapest [Comodo certificates](https://codesigncert.com/comodocodesigning) is OK. Because 97 | the Niagara System Trust Store stores the Comodo CA root certificate, you do not have to deploy your 98 | CA-signed certificate along with your module. 99 | 100 | A short how to for self-signed certificates (OK for development): 101 | 102 | 1. In the Gradle file `envasCommons-rt.gradle` replace the `cert-alias` with a name identifying your 103 | code signing entry (e.g. private/public key pair) in the keystore. Example: 104 | 105 | ``` 106 | niagaraModule { 107 | preferredSymbol = "env" 108 | moduleName = "envasCommons" 109 | runtimeProfile = "rt" 110 | certAlias = "mycompany-code-sign" 111 | } 112 | ``` 113 | 114 | 2. Execute the Gradle `jar` task. In the directory `~/.tridium/security` you will find the following 115 | new keystore with your new private/public keypair and the XML file describing your security profile with 116 | the keystore and private key passwords. 117 | 118 | ``` 119 | mycompany_signing.jks 120 | mycompany_signing.xml 121 | ``` 122 | 123 | 3. Use the [Keystore Explorer](https://keystore-explorer.org) to review the keystore entries 124 | and to export the self-signed certificate. 125 | 126 | 4. Import the exported certificate into your Workbench and into any station platform running `envasCommons`. 127 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Neopsis GmbH. All Rights Reserved. 3 | */ 4 | 5 | repositories { 6 | maven(url = providers.gradleProperty("niagaraToolsHome").get() + "/gradlePlugins") 7 | maven(url = uri("https://repo.repsy.io/mvn/neopsis/niagara")) 8 | mavenCentral() 9 | gradlePluginPortal() 10 | } 11 | 12 | plugins { 13 | id("com.neopsis.niagara-project-plugin") 14 | } 15 | 16 | bundle { 17 | description = "Envas Commons" 18 | moduleName = "envasCommons" 19 | moduleVersion = "0.5" 20 | } 21 | 22 | 23 | niagaraSigning { 24 | aliases.set(listOf(providers.gradleProperty("signingCertificateAlias").get())) 25 | signingProfileFile.set(file(providers.gradleProperty("signingProfileFile").get())) 26 | } 27 | 28 | 29 | //////////////////////////////////////////////////////////////// 30 | // Dependencies and configurations... configuration 31 | //////////////////////////////////////////////////////////////// 32 | 33 | subprojects { 34 | repositories { 35 | mavenCentral() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/envasCommons-rt.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Neopsis GmbH. All Rights Reserved. 3 | */ 4 | 5 | import com.tridium.gradle.plugins.module.util.ModulePart.RuntimeProfile.rt 6 | import com.tridium.gradle.plugins.niagara.NiagaraProjectLayout 7 | import org.gradle.internal.impldep.org.junit.experimental.categories.Categories.CategoryFilter.exclude 8 | import java.time.LocalDate 9 | 10 | plugins { 11 | id("com.neopsis.niagara-module-plugin") 12 | } 13 | 14 | description = "Envas - Commons for Niagara4" 15 | 16 | moduleManifest { 17 | preferredSymbol.set("env") 18 | moduleName.set("envasCommons") 19 | runtimeProfile.set(rt) 20 | } 21 | 22 | niagaraProject { 23 | niagaraProjectLayout.set(NiagaraProjectLayout.NIAGARA_MAVEN) 24 | } 25 | 26 | dependencies { 27 | 28 | nre(":nre") 29 | api(":baja") 30 | 31 | uberjar("net.engio:mbassador:1.3.2") 32 | uberjar("com.alibaba:fastjson:1.2.73") 33 | 34 | testImplementation("junit:junit:4.12") { 35 | exclude(group="org.hamcrest") 36 | } 37 | testImplementation("org.hamcrest:hamcrest-library:1.3") 38 | } 39 | 40 | tasks.clean { 41 | delete += listOf("build", "out") 42 | } 43 | 44 | tasks.jar { 45 | 46 | includeEmptyDirs = true 47 | 48 | exclude("maven/") 49 | exclude("services/") 50 | exclude("NOTICE.txt") 51 | exclude("META-INF/services/**") 52 | exclude("META-INF/maven/**") 53 | exclude("META-INF/NOTICE.txt") 54 | 55 | } 56 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/module-include.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/module-permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LOGGING 6 | Everybody needs to write to application log. 7 | 8 | 9 | 10 | REFLECTION 11 | Message bus needs reflection. 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/NvAbstractLicense.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvAbstractLicense.java 06.10.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license; 12 | 13 | import com.alibaba.fastjson.annotation.JSONField; 14 | 15 | import com.neopsis.envas.commons.license.util.LicenseUtils; 16 | 17 | import java.security.GeneralSecurityException; 18 | 19 | /** 20 | * Subclasses should add license specific fields. 21 | * All licenses have a signature, it's here. 22 | * 23 | */ 24 | public abstract class NvAbstractLicense { 25 | 26 | /////////////////////////////////////////////////////////////////////////////////////////// 27 | // Fields 28 | /////////////////////////////////////////////////////////////////////////////////////////// 29 | @JSONField(name = "signature") 30 | protected String signature; 31 | 32 | /////////////////////////////////////////////////////////////////////////////////////////// 33 | // Constructors 34 | /////////////////////////////////////////////////////////////////////////////////////////// 35 | public NvAbstractLicense() {} 36 | 37 | public NvAbstractLicense(String signature) { 38 | this.signature = signature; 39 | } 40 | 41 | /////////////////////////////////////////////////////////////////////////////////////////// 42 | // Getters/Setters 43 | /////////////////////////////////////////////////////////////////////////////////////////// 44 | public String getSignature() { 45 | return signature; 46 | } 47 | 48 | public void setSignature(String signature) { 49 | this.signature = signature; 50 | } 51 | 52 | /** 53 | * Sign the license with the PRIVATE_KEY. This is a shortcut for LicenseUtils.sign(...) 54 | * 55 | * @param PRIVATE_KEY private key as a hex string 56 | * @throws GeneralSecurityException 57 | */ 58 | public void sign(final String PRIVATE_KEY) throws GeneralSecurityException { 59 | LicenseUtils.sign(this, PRIVATE_KEY); 60 | } 61 | 62 | /** 63 | * Sign the license with the PRIVATE_KEY and algorithm. This is a shortcut for LicenseUtils.sign(...) 64 | * 65 | * @param PRIVATE_KEY private key as a hex string 66 | * @param sigAlgorithm algorithm for the signature (SHA1withDSA, ...) 67 | * @param provider algorithm provider (SUN, ...) 68 | * @throws GeneralSecurityException 69 | */ 70 | public void sign(final String PRIVATE_KEY, String sigAlgorithm, String provider) throws GeneralSecurityException { 71 | LicenseUtils.sign(this, PRIVATE_KEY, sigAlgorithm, provider); 72 | } 73 | 74 | /** 75 | * Verify the license signature using a public key. This is a shortcut for 76 | * LicenseUtils.verify(this, publicKey); 77 | * 78 | * @param PUBLIC_KEY public key as string 79 | * @throws GeneralSecurityException security exception with error message 80 | */ 81 | public boolean verify(String PUBLIC_KEY) throws GeneralSecurityException { 82 | return LicenseUtils.verify(this, PUBLIC_KEY); 83 | } 84 | 85 | /** 86 | * Verify the license signature using a public key. This is a shortcut for 87 | * LicenseUtils.verify(this, publicKey, algorithm, provider); 88 | * 89 | * @param PUBLIC_KEY public key as string 90 | * @throws GeneralSecurityException security exception with error message 91 | */ 92 | public boolean verify(String PUBLIC_KEY, String sigAlgorithm, String provider) throws GeneralSecurityException { 93 | return LicenseUtils.verify(this, PUBLIC_KEY, sigAlgorithm, provider); 94 | } 95 | 96 | /** 97 | * Parsing callback called after the license object was created and before 98 | * the object will be filled with parsed data. Default - do nothing 99 | */ 100 | public void beforeDeserialize() { 101 | 102 | // 103 | } 104 | 105 | /** 106 | * Parsing callback called after parsing was finished. Default - do nothing 107 | */ 108 | public void afterDeserialize() { 109 | 110 | // 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return LicenseUtils.toJson(this); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/NvLicense.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvLicense.java 06.10.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license; 12 | 13 | import com.alibaba.fastjson.annotation.JSONField; 14 | import com.neopsis.envas.commons.license.util.JulianDateCodec; 15 | import com.tridium.sys.Nre; 16 | 17 | import javax.baja.license.Feature; 18 | import java.security.GeneralSecurityException; 19 | import java.util.ArrayList; 20 | import java.util.Date; 21 | import java.util.List; 22 | 23 | /** 24 | * Tridium license reference implementation 25 | * 26 | */ 27 | public class NvLicense extends NvAbstractLicense { 28 | 29 | @JSONField(name = "vendor") 30 | private String vendor; 31 | @JSONField(name = "hostId") 32 | private String hostId; 33 | @JSONField( 34 | name = "expiration", 35 | serializeUsing = JulianDateCodec.class, 36 | deserializeUsing = JulianDateCodec.class 37 | ) 38 | public long expiration; 39 | @JSONField( 40 | name = "generated", 41 | serializeUsing = JulianDateCodec.class, 42 | deserializeUsing = JulianDateCodec.class 43 | ) 44 | private long generated; 45 | @JSONField(name = "version") 46 | private String version; 47 | @JSONField(name = "features") 48 | private List features; 49 | 50 | /** 51 | * Default constructor - reflection needs it 52 | */ 53 | public NvLicense() { 54 | generated = new Date().getTime(); 55 | } 56 | 57 | /** 58 | * Constructor creates new license object without features 59 | * 60 | * @param vendor vendor 61 | * @param hostId host ID 62 | * @param expDate expiration date 63 | * @param version version 64 | * 65 | */ 66 | public NvLicense(String vendor, String hostId, long expDate, String version) { 67 | 68 | this(); 69 | this.vendor = vendor; 70 | this.hostId = hostId; 71 | expiration = expDate; 72 | this.version = version; 73 | } 74 | 75 | /** 76 | * Constructor creates new license object including features 77 | * 78 | * @param vendor vendor 79 | * @param hostId host ID 80 | * @param expDate expiration date 81 | * @param version version 82 | * 83 | * @param ftr features 84 | * 85 | */ 86 | public NvLicense(String vendor, String hostId, long expDate, String version, List ftr) { 87 | 88 | this(); 89 | this.vendor = vendor; 90 | this.hostId = hostId; 91 | expiration = expDate; 92 | this.version = version; 93 | features = ftr; 94 | } 95 | 96 | /////////////////////////////////////////////////////////////////////////////////////////// 97 | // Setters and Getters 98 | /////////////////////////////////////////////////////////////////////////////////////////// 99 | public String getVendor() { 100 | return vendor; 101 | } 102 | 103 | public void setVendor(String vendor) { 104 | this.vendor = vendor; 105 | } 106 | 107 | public String getHostId() { 108 | return hostId; 109 | } 110 | 111 | public NvLicense setHostId(String hostId) { 112 | 113 | this.hostId = hostId; 114 | 115 | return this; 116 | } 117 | 118 | public void setExpiration(long expDate) { 119 | this.expiration = expDate; 120 | } 121 | 122 | @JSONField(serialize = false, deserialize = false) 123 | public void setExpirationDate(Date expDate) { 124 | this.expiration = expDate.getTime(); 125 | } 126 | 127 | public void setGenerated(long genDate) { 128 | this.generated = genDate; 129 | } 130 | 131 | @JSONField(serialize = false, deserialize = false) 132 | public void setGeneratedDate(Date genDate) { 133 | this.generated = genDate.getTime(); 134 | } 135 | 136 | public long getExpiration() { 137 | return expiration; 138 | } 139 | 140 | public long getGenerated() { 141 | return generated; 142 | } 143 | 144 | @JSONField(serialize = false, deserialize = false) 145 | public Date getExpirationDate() { 146 | return new Date(expiration); 147 | } 148 | 149 | @JSONField(serialize = false, deserialize = false) 150 | public Date getGeneratedDate() { 151 | return new Date(generated); 152 | } 153 | 154 | public String getVersion() { 155 | return version; 156 | } 157 | 158 | public void setVersion(String version) { 159 | this.version = version; 160 | } 161 | 162 | public List getFeatures() { 163 | return features; 164 | } 165 | 166 | public void setFeatures(List features) { 167 | this.features = features; 168 | } 169 | 170 | /////////////////////////////////////////////////////////////////////////////////////////// 171 | // Features utils 172 | /////////////////////////////////////////////////////////////////////////////////////////// 173 | 174 | /** 175 | * There is no updateFeature() or deleteFeature() methods. We assume a license will 176 | * be always created from scratch using an entry form or a database as the data source. 177 | * 178 | */ 179 | 180 | /** 181 | * Adds a license feature to the license. This is a facade for the features.add() method 182 | * 183 | * @param feature license feature object 184 | */ 185 | public void addFeature(NvLicenseFeature feature) { 186 | 187 | if (feature == null) { 188 | return; 189 | } 190 | 191 | if (features == null) { 192 | features = new ArrayList<>(); 193 | } 194 | 195 | features.add(feature); 196 | } 197 | 198 | @JSONField(serialize = false, deserialize = false) 199 | public Feature getFeature(String featureName) { 200 | 201 | if (features == null) { 202 | return null; 203 | } 204 | 205 | for (NvLicenseFeature feature : features) { 206 | 207 | if (feature.getFeatureName().equals(featureName)) { 208 | return feature; 209 | } 210 | } 211 | 212 | return null; 213 | } 214 | 215 | /////////////////////////////////////////////////////////////////////////////////////////// 216 | // Generate/Validate Utilities 217 | /////////////////////////////////////////////////////////////////////////////////////////// 218 | 219 | /** 220 | * Check if the license is valid 221 | * 222 | */ 223 | public void check(String publicKey) throws GeneralSecurityException { 224 | 225 | checkExpiration(); 226 | validateHostId(Nre.getHostId().toLowerCase()); 227 | if( !verify(publicKey)) { 228 | throw new GeneralSecurityException("Envas license is not valid or has been tampered with since it was created!"); 229 | }; 230 | } 231 | 232 | /** 233 | * Check license current expiration 234 | * 235 | * @throws GeneralSecurityException security exception with error message 236 | */ 237 | public void checkExpiration(long checkDate) throws GeneralSecurityException { 238 | checkExpiration(new Date(checkDate)); 239 | } 240 | 241 | /** 242 | * Check license current expiration 243 | * 244 | * @throws GeneralSecurityException security exception with error message 245 | */ 246 | public void checkExpiration() throws GeneralSecurityException { 247 | checkExpiration(new Date()); 248 | } 249 | 250 | /** 251 | * Check license expiration at some given date 252 | * 253 | * @param checkDate date to check expiration 254 | * @throws GeneralSecurityException security exception with error message 255 | */ 256 | public void checkExpiration(Date checkDate) throws GeneralSecurityException { 257 | 258 | if (checkDate == null) { 259 | throw new GeneralSecurityException("Missing license expiration"); 260 | } 261 | 262 | if (checkDate.getTime() > expiration) { 263 | throw new GeneralSecurityException("License expired"); 264 | } 265 | } 266 | 267 | /** 268 | * Check the Niagara HostId. 269 | * 270 | * @throws GeneralSecurityException security exception with error message 271 | */ 272 | public void validateHostId(String checkHostId) throws GeneralSecurityException { 273 | 274 | if (checkHostId == null) { 275 | throw new GeneralSecurityException("License HostId check failed, checked HostId is null"); 276 | } 277 | 278 | if (!hostId.equalsIgnoreCase(checkHostId)) { 279 | throw new GeneralSecurityException("Invalid Host ID"); 280 | } 281 | } 282 | 283 | 284 | /////////////////////////////////////////////////////////////////////////////////////////// 285 | // Fields 286 | /////////////////////////////////////////////////////////////////////////////////////////// 287 | } 288 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/NvLicenseFeature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvLicenseFeature.java 06.10.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license; 12 | 13 | import com.alibaba.fastjson.annotation.JSONField; 14 | 15 | import com.neopsis.envas.commons.license.util.JulianDateCodec; 16 | 17 | import com.tridium.sys.license.LicenseUtil; 18 | 19 | import javax.baja.license.Feature; 20 | import javax.baja.license.FeatureLicenseExpiredException; 21 | import javax.baja.license.FeatureNotLicensedException; 22 | import javax.baja.sys.Clock; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Date; 26 | import java.util.HashMap; 27 | 28 | /** 29 | * Tridium license feature interface implementation. 30 | * 31 | */ 32 | public class NvLicenseFeature implements Feature, Comparable { 33 | 34 | @JSONField(name = "vendor") 35 | String vendorName = null; 36 | @JSONField(name = "feature") 37 | String featureName = null; 38 | @JSONField( 39 | name = "expiration", 40 | serializeUsing = JulianDateCodec.class, 41 | deserializeUsing = JulianDateCodec.class 42 | ) 43 | long expiration; 44 | @JSONField(name = "options") 45 | HashMap options = null; 46 | 47 | /** 48 | * Default constructor for reflection tools 49 | */ 50 | public NvLicenseFeature() { 51 | options = new HashMap<>(); 52 | } 53 | 54 | /** 55 | * Constructor without expiration and options 56 | * 57 | * @param vendorName vendorName name 58 | * @param featureName feature name 59 | */ 60 | public NvLicenseFeature(final String vendorName, final String featureName) { 61 | 62 | this.vendorName = vendorName; 63 | this.featureName = featureName; 64 | } 65 | 66 | /** 67 | * Constructor without options 68 | * 69 | * @param vendorName vendorName name 70 | * @param featureName feature name 71 | * @param expDate expiration date 72 | */ 73 | public NvLicenseFeature(final String vendorName, final String featureName, final long expDate) { 74 | 75 | this.vendorName = vendorName; 76 | this.featureName = featureName; 77 | this.expiration = expDate; 78 | } 79 | 80 | /** 81 | * Constructor with options 82 | * 83 | * @param vendorName vendorName name 84 | * @param featureName feature name 85 | * @param expDate expiration date 86 | * @param options options map 87 | */ 88 | public NvLicenseFeature(final String vendorName, final String featureName, final long expDate, 89 | HashMap options) { 90 | 91 | this.vendorName = vendorName; 92 | this.featureName = featureName; 93 | this.expiration = expDate; 94 | this.options = options; 95 | } 96 | 97 | /////////////////////////////////////////////////////////////////////////////////////////// 98 | // Getters and Setters 99 | /////////////////////////////////////////////////////////////////////////////////////////// 100 | public void setVendorName(String vendorName) { 101 | this.vendorName = vendorName; 102 | } 103 | 104 | public void setFeatureName(String featureName) { 105 | this.featureName = featureName; 106 | } 107 | 108 | public void setExpiration(long expDate) { 109 | this.expiration = expDate; 110 | } 111 | 112 | @JSONField(serialize = false, deserialize = false) 113 | public void setExpirationDate(Date expDate) { 114 | this.expiration = expDate.getTime(); 115 | } 116 | 117 | @JSONField(serialize = false, deserialize = false) 118 | public Date getExpirationDate() { 119 | return new Date(expiration); 120 | } 121 | 122 | public HashMap getOptions() { 123 | return options; 124 | } 125 | 126 | public void setOptions(HashMap options) { 127 | this.options = options; 128 | } 129 | 130 | @JSONField(serialize = false, deserialize = false) 131 | public boolean isExpired(long expDate) { 132 | return this.expiration < expDate; 133 | } 134 | 135 | /////////////////////////////////////////////////////////////////////////////////////////// 136 | // Options interface 137 | /////////////////////////////////////////////////////////////////////////////////////////// 138 | 139 | /** 140 | * Add a featureName option 141 | * 142 | * @param key option key 143 | * @param value option value 144 | */ 145 | public void addOption(String key, Object value) { 146 | addOption(key, value, null); 147 | } 148 | 149 | /** 150 | * Add a featureName option 151 | * 152 | * @param key option key 153 | * @param value option value 154 | */ 155 | public void addOption(String key, Object value, Object defaultValue) { 156 | 157 | if ((value == null) && (defaultValue == null)) { 158 | return; 159 | } 160 | 161 | if (options == null) { 162 | options = new HashMap<>(); 163 | } 164 | 165 | if (value == null) { 166 | options.put(key, defaultValue); 167 | } else { 168 | options.put(key, value); 169 | } 170 | } 171 | 172 | /////////////////////////////////////////////////////////////////////////////////////////// 173 | // Tridium interface implementation 174 | /////////////////////////////////////////////////////////////////////////////////////////// 175 | 176 | /** 177 | * This belongs to getters but is defined in the Tridium interface, that's why it's here 178 | * 179 | * @return feature name 180 | */ 181 | public String getFeatureName() { 182 | return featureName; 183 | } 184 | 185 | /** 186 | * This belongs to getters but is defined in the Tridium interface, that's why it's here 187 | * 188 | * @return vendor name 189 | */ 190 | @Override 191 | public String getVendorName() { 192 | 193 | // compatibility with 1.0 194 | if (vendorName == null) { 195 | return "neopsis"; 196 | } 197 | 198 | return vendorName; 199 | } 200 | 201 | @Override 202 | public long getExpiration() { 203 | return expiration; 204 | } 205 | 206 | @Override 207 | public int compareTo(NvLicenseFeature f) { 208 | return this.featureName.compareTo(f.getFeatureName()); 209 | } 210 | 211 | @JSONField(serialize = false, deserialize = false) 212 | @Override 213 | public boolean isExpired() { 214 | return this.expiration < Clock.millis(); 215 | } 216 | 217 | /** 218 | * Check the featureName validity. 219 | * Invalid featureName throws {@link FeatureNotLicensedException} 220 | * 221 | * @throws FeatureNotLicensedException thrown if featureName is not licensed 222 | */ 223 | @Override 224 | public void check() throws FeatureNotLicensedException { 225 | 226 | if (this.isExpired()) { 227 | throw new FeatureLicenseExpiredException(this.toString()); 228 | } 229 | } 230 | 231 | /** 232 | * Returns a list of option names as String array. 233 | * 234 | * @return names of all options in a String array 235 | */ 236 | @Override 237 | public String[] list() { 238 | 239 | ArrayList lst = new ArrayList<>(); 240 | 241 | for (String key : options.keySet()) { 242 | lst.add(key); 243 | } 244 | 245 | lst.trimToSize(); 246 | 247 | return lst.toArray(new String[lst.size()]); 248 | } 249 | 250 | /** 251 | * Returns a string option 252 | * 253 | * @param option option key 254 | */ 255 | @Override 256 | public String get(String option) { 257 | 258 | Object oval = options.get(option); 259 | 260 | if (oval instanceof String) { 261 | return (String) oval; 262 | } 263 | 264 | return oval.toString(); 265 | } 266 | 267 | /** 268 | * Returns a string option or a default value if option 269 | * not available 270 | * 271 | * @param option option key 272 | * @param def default option value 273 | */ 274 | @Override 275 | public String get(String option, String def) { 276 | 277 | String value = get(option); 278 | 279 | if (value == null) { 280 | return def; 281 | } 282 | 283 | return value; 284 | } 285 | 286 | /** 287 | * Returns a boolean option or a default value if option 288 | * not available 289 | * 290 | * @param option option key 291 | * @param def default option value 292 | */ 293 | @Override 294 | public boolean getb(String option, boolean def) { 295 | 296 | String value = get(option); 297 | 298 | if (value == null) { 299 | return def; 300 | } 301 | 302 | value = value.toLowerCase(); 303 | 304 | if (value.equals("true")) { 305 | return true; 306 | } 307 | 308 | if (value.equals("false")) { 309 | return false; 310 | } 311 | 312 | if (value.equals("0")) { 313 | return false; 314 | } 315 | 316 | if (value.equals("1")) { 317 | return true; 318 | } 319 | 320 | throw new IllegalStateException("Invalid boolean " + value); 321 | } 322 | 323 | /** 324 | * Returns an integer option or a default value if option 325 | * not available 326 | * 327 | * @param option option key 328 | * @param def default option value 329 | */ 330 | @Override 331 | public int geti(String option, int def) { 332 | 333 | final String value = this.get(option); 334 | 335 | if (value == null) { 336 | return def; 337 | } 338 | 339 | return Integer.parseInt(value); 340 | } 341 | 342 | @Override 343 | public String toString() { 344 | 345 | String exp; 346 | 347 | if (this.expiration == Long.MAX_VALUE) { 348 | exp = "never"; 349 | } else { 350 | exp = LicenseUtil.formatDate(this.expiration); 351 | } 352 | 353 | if (this.isExpired()) { 354 | return featureName + " [expired: " + exp + "]"; 355 | } 356 | 357 | return featureName + " [expires: " + exp + "]"; 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/NvLicenseLocalManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvLicenseLocalManager.java 11.07.2016 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license; 12 | 13 | import com.neopsis.envas.commons.license.util.LicenseUtils; 14 | import com.neopsis.envas.util.NvLog; 15 | 16 | import javax.baja.sys.Sys; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | 21 | import java.security.GeneralSecurityException; 22 | 23 | import java.util.ArrayList; 24 | 25 | /** 26 | * License Manager implementation for licenses saved in a local file store 27 | * 28 | */ 29 | public class NvLicenseLocalManager extends NvLicenseManager { 30 | 31 | private NvLicenseLocalManager() { 32 | 33 | // private constructor, use factory method make() to create INSTANCEs 34 | } 35 | 36 | public static NvLicenseLocalManager make(String publicKey) { 37 | 38 | NvLicenseLocalManager lm = new NvLicenseLocalManager(); 39 | 40 | lm.setPublicKey(publicKey); 41 | lm.reload(); 42 | 43 | return lm; 44 | } 45 | 46 | /** 47 | * License Local Manager loads the licenses from local file store. 48 | * This method returns array of all licenses found in all license files. 49 | * The license file must have the extension *.l4e. 50 | */ 51 | @Override 52 | protected NvLicense[] loadLicenses() { 53 | 54 | final ArrayList licenses = new ArrayList(); 55 | final File dir = Sys.getNiagaraSharedUserHome(); 56 | final File[] files = dir.listFiles(); 57 | 58 | for (int i = 0; (files != null) && (i < files.length); ++i) { 59 | 60 | if (files[i].getName().toLowerCase().endsWith(".l4e")) { 61 | 62 | try { 63 | 64 | NvLicense lic = loadLicense(files[i]); 65 | 66 | if (lic != null) { 67 | licenses.add(lic); 68 | } 69 | 70 | } catch (Exception e) { 71 | NvLog.error("Error reading license file " + e.getMessage()); 72 | } 73 | } 74 | } 75 | 76 | return licenses.toArray(new NvLicense[licenses.size()]); 77 | } 78 | 79 | private NvLicense loadLicense(File file) 80 | throws IOException, IllegalAccessException, GeneralSecurityException, InstantiationException { 81 | return LicenseUtils.readLicense(file.getPath(), NvLicense.class); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/NvLicenseManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvLicenseManager.java 07.07.2016 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license; 12 | 13 | import com.neopsis.envas.util.NvLog; 14 | 15 | import com.tridium.sys.license.LicenseUtil; 16 | 17 | import javax.baja.license.Feature; 18 | import javax.baja.license.FeatureNotLicensedException; 19 | import javax.baja.license.LicenseDatabaseException; 20 | import javax.baja.license.LicenseManager; 21 | import javax.baja.nre.util.SortUtil; 22 | 23 | import java.security.GeneralSecurityException; 24 | 25 | import java.util.HashMap; 26 | import java.util.List; 27 | 28 | /** 29 | * License Manager saves all licensed features from all vendors. 30 | * Licensed features are accessible via simple API 31 | *
  • {@link NvLicenseManager#getFeature} 32 | *
  • {@link NvLicenseManager#checkFeature} 33 | *
  • {@link NvLicenseManager#getFeatures()} 34 | *

    35 | * All features from validated licenses (license HostId, 36 | * signature and expiration are OK), but features itself can be 37 | * invalid (expired) 38 | * 39 | */ 40 | public abstract class NvLicenseManager implements LicenseManager { 41 | 42 | private HashMap features; 43 | 44 | /** 45 | * License Manager uses factory method make() 46 | * to create a new instance 47 | */ 48 | protected NvLicenseManager() {} 49 | 50 | /** 51 | * Returns all licenses form license store, implemented 52 | * by subclasses 53 | * 54 | * @return array of licenses 55 | */ 56 | protected abstract NvLicense[] loadLicenses(); 57 | 58 | /** 59 | * Reloads licenses from the license store 60 | * 61 | */ 62 | protected void reload() { 63 | this.load(); 64 | } 65 | 66 | /** 67 | * Loads all valid features into the fresh initialized 68 | * feature map 69 | */ 70 | protected final void load() { 71 | 72 | features = new HashMap(); 73 | setFeatures(loadLicenses()); 74 | } 75 | 76 | /** 77 | * Add all valid features into the feature list. 78 | * 79 | * @param licenses array with all licenses loaded from license store 80 | */ 81 | protected final void setFeatures(final NvLicense[] licenses) { 82 | 83 | for (int i = 0; i < licenses.length; i++) { 84 | 85 | NvLicense lic = licenses[i]; 86 | 87 | try { 88 | 89 | lic.check(publicKey); 90 | 91 | List licFeatures = lic.getFeatures(); 92 | 93 | for (NvLicenseFeature ftr : licFeatures) { 94 | features.put(LicenseUtil.toKey(ftr.getVendorName(), ftr.getFeatureName()), ftr); 95 | } 96 | 97 | } catch (GeneralSecurityException e) { 98 | NvLog.error("License validation failed: " + e.getMessage()); 99 | } 100 | } 101 | } 102 | 103 | /** 104 | * Returns a vendor feature or raise an exception if feature does not exist. 105 | * Does not make a validation check 106 | * 107 | * @param vendor owner of the feature 108 | * @param feature feature name 109 | */ 110 | public Feature getFeature(final String vendor, final String feature) 111 | throws FeatureNotLicensedException, LicenseDatabaseException { 112 | 113 | final String key = LicenseUtil.toKey(vendor, feature); 114 | final Feature licFeature = (Feature) this.features.get(key); 115 | 116 | if (licFeature == null) { 117 | throw new FeatureNotLicensedException(key); 118 | } 119 | 120 | return licFeature; 121 | } 122 | 123 | /** 124 | * Returns a vendor feature or raise an exception if feature does not exist or 125 | * if the feature is not valid (expired). 126 | * 127 | * @param vendor owner of the feature 128 | * @param feature feature name 129 | */ 130 | @Override 131 | public Feature checkFeature(String vendor, String feature) throws FeatureNotLicensedException, LicenseDatabaseException { 132 | 133 | Feature licFeature = getFeature(vendor, feature); 134 | 135 | licFeature.check(); 136 | 137 | return licFeature; 138 | } 139 | 140 | /** 141 | * Returns all features as array 142 | * 143 | * @return array with all features registered in this License Manager 144 | */ 145 | @Override 146 | public Feature[] getFeatures() throws LicenseDatabaseException { 147 | 148 | final NvLicenseFeature[] temp = this.features.values().toArray(new NvLicenseFeature[this.features.size()]); 149 | final String[] keys = new String[temp.length]; 150 | 151 | for (int i = 0; i < keys.length; ++i) { 152 | keys[i] = LicenseUtil.toKey(temp[i].getVendorName(), temp[i].getFeatureName()); 153 | } 154 | 155 | SortUtil.sort((Object[]) keys, (Object[]) temp, true); 156 | 157 | return (Feature[]) temp; 158 | } 159 | 160 | public void setPublicKey(String pk) { 161 | publicKey = pk; 162 | } 163 | 164 | /////////////////////////////////////////////////////////////////////////////////////////// 165 | // Fields 166 | /////////////////////////////////////////////////////////////////////////////////////////// 167 | private String publicKey = ""; 168 | } 169 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/util/ByteHex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)ByteHex.java 18.08.2016 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license.util; 12 | 13 | import java.io.ByteArrayOutputStream; 14 | 15 | /** 16 | * Utility class for converting byte arrays to and from a Hex string 17 | * 18 | * Robert Carnecky, Neopsis 19 | */ 20 | public final class ByteHex { 21 | 22 | private static final char[] hexs = { 23 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 24 | }; 25 | 26 | /** 27 | * Convert a byte array into a printable format containing a 28 | * String of hexadecimal digit characters (two per byte). 29 | * 30 | * @param bytes Byte array representation 31 | * @return Hex string 32 | */ 33 | public static String convert(byte bytes[]) { 34 | 35 | StringBuffer sb = new StringBuffer(bytes.length * 2); 36 | 37 | for (int i = 0; i < bytes.length; i++) { 38 | 39 | sb.append(hexs[(bytes[i] >> 4) & 0x0f]); 40 | sb.append(hexs[bytes[i] & 0x0f]); 41 | } 42 | 43 | return (sb.toString()); 44 | } 45 | 46 | /** 47 | * Convert a Hex String into the corresponding byte array by encoding 48 | * each two hexadecimal digits as a byte. 49 | * 50 | * @param hex Hexadecimal digits representation 51 | * @return byte Byte array 52 | */ 53 | public static byte[] convert(String hex) throws IllegalArgumentException { 54 | 55 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 56 | 57 | for (int i = 0; i < hex.length(); i += 2) { 58 | 59 | char c1 = hex.charAt(i); 60 | 61 | if ((i + 1) >= hex.length()) { 62 | throw new IllegalArgumentException(); 63 | } 64 | 65 | char c2 = hex.charAt(i + 1); 66 | byte b = 0; 67 | 68 | if ((c1 >= '0') && (c1 <= '9')) { 69 | b += ((c1 - '0') * 16); 70 | } else if ((c1 >= 'a') && (c1 <= 'f')) { 71 | b += ((c1 - 'a' + 10) * 16); 72 | } else if ((c1 >= 'A') && (c1 <= 'F')) { 73 | b += ((c1 - 'A' + 10) * 16); 74 | } else { 75 | throw new IllegalArgumentException(); 76 | } 77 | 78 | if ((c2 >= '0') && (c2 <= '9')) { 79 | b += (c2 - '0'); 80 | } else if ((c2 >= 'a') && (c2 <= 'f')) { 81 | b += (c2 - 'a' + 10); 82 | } else if ((c2 >= 'A') && (c2 <= 'F')) { 83 | b += (c2 - 'A' + 10); 84 | } else { 85 | throw new IllegalArgumentException(); 86 | } 87 | 88 | baos.write(b); 89 | } 90 | 91 | return (baos.toByteArray()); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/util/JulianDateCodec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)JulianDateCodec.java 10.10.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license.util; 12 | 13 | import com.alibaba.fastjson.parser.DefaultJSONParser; 14 | import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; 15 | import com.alibaba.fastjson.serializer.JSONSerializer; 16 | import com.alibaba.fastjson.serializer.ObjectSerializer; 17 | import com.alibaba.fastjson.serializer.SerializeWriter; 18 | 19 | import java.io.IOException; 20 | 21 | import java.lang.reflect.Type; 22 | 23 | import java.text.DateFormat; 24 | import java.text.ParseException; 25 | import java.text.SimpleDateFormat; 26 | 27 | import java.util.Date; 28 | 29 | /** 30 | * Serializes and deserializes the long (julian) date. 31 | * 32 | */ 33 | public class JulianDateCodec implements ObjectSerializer, ObjectDeserializer { 34 | 35 | DateFormat df = new SimpleDateFormat(LicenseUtils.DATE_FORMAT); 36 | 37 | /** 38 | * Generates the long value from the date string. Sets Long.MAX_VALUE 39 | * for dooms day. 40 | * 41 | * @param parser JSON parser 42 | * @param type type (Class) of the object 43 | * @param fieldName field name in case of beans 44 | * @param returning type (long) 45 | * 46 | * @return deserialized object 47 | */ 48 | @Override 49 | public T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { 50 | 51 | Long longObject; 52 | DateFormat df = new SimpleDateFormat(LicenseUtils.DATE_FORMAT); 53 | String value = parser.parseObject(String.class); 54 | 55 | if (value.equals("never")) { 56 | longObject = Long.MAX_VALUE; 57 | } else { 58 | 59 | Date dat = null; 60 | 61 | try { 62 | dat = df.parse(value); 63 | } catch (ParseException e) { 64 | return null; 65 | } 66 | 67 | longObject = dat.getTime(); 68 | } 69 | 70 | return (T) longObject; 71 | } 72 | 73 | @Override 74 | public int getFastMatchToken() { 75 | return 0; 76 | } 77 | 78 | /** 79 | * Write the long (julian) date as string 80 | * 81 | * @param serializer JSON serializer 82 | * @param object serialized object 83 | * @param fieldName field name in case of beans 84 | * @param fieldType field type (class) 85 | * @param features optinal features 86 | * 87 | * @throws IOException 88 | */ 89 | @Override 90 | public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { 91 | 92 | SerializeWriter out = serializer.out; 93 | long value = (long) object; 94 | 95 | if (value == Long.MAX_VALUE) { 96 | out.writeString("never"); 97 | } else { 98 | out.writeString(df.format(new Date(value))); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/commons/license/util/LicenseUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)LicenseUtils.java 06.10.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.commons.license.util; 12 | 13 | import com.alibaba.fastjson.JSON; 14 | import com.alibaba.fastjson.parser.ParserConfig; 15 | import com.alibaba.fastjson.serializer.JSONSerializer; 16 | import com.alibaba.fastjson.serializer.SerializeConfig; 17 | import com.alibaba.fastjson.serializer.SerializeWriter; 18 | import com.alibaba.fastjson.serializer.SerializerFeature; 19 | import com.neopsis.envas.commons.license.NvAbstractLicense; 20 | 21 | import javax.crypto.KeyGenerator; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | import java.nio.file.Paths; 26 | import java.security.*; 27 | import java.security.spec.InvalidKeySpecException; 28 | import java.security.spec.PKCS8EncodedKeySpec; 29 | import java.security.spec.X509EncodedKeySpec; 30 | 31 | /** 32 | * Utilities supporting licensing framework 33 | * 34 | */ 35 | public class LicenseUtils { 36 | 37 | /** 38 | * Default values 39 | */ 40 | public static final String KPG_ALGORITHM = "DSA"; 41 | public static final String PROVIDER = "SUN"; 42 | public static final String RNG_ALGORITHM = "SHA1PRNG"; 43 | public static final String SIG_ALGORITHM = "SHA1withDSA"; 44 | public static final int KEYLEN = 1024; 45 | public static final String DATE_FORMAT = "yyyy-MM-dd"; 46 | 47 | /** 48 | * 49 | * 50 | */ 51 | public LicenseUtils() { 52 | 53 | // 54 | } 55 | 56 | /** 57 | * Test if unlimited strength policy is supported. Java Cryptography Extension (JCE) 58 | * Unlimited Strength Jurisdiction Policy Files are required to use PGP encryption 59 | * and may be required by some connectors. 60 | * 61 | * @return true if unlimited strength policy is supported 62 | */ 63 | public static boolean isUnlimitedSupported() { 64 | 65 | boolean isSupported = false; 66 | 67 | try { 68 | 69 | KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunJCE"); 70 | 71 | kgen.init(256); 72 | isSupported = true; 73 | 74 | } catch (NoSuchAlgorithmException e) { 75 | isSupported = false; 76 | } catch (NoSuchProviderException e) { 77 | isSupported = false; 78 | } 79 | 80 | return isSupported; 81 | } 82 | 83 | /////////////////////////////////////////////////////////////////////////////////////////// 84 | // Private/Public Key generator 85 | /////////////////////////////////////////////////////////////////////////////////////////// 86 | 87 | /** 88 | * Returns the public key from the encoded byte array using default arguments 89 | * 90 | *

      91 | *
    • key pair algorithm = DSA
    • 92 | *
    • provider = SUN
    • 93 | *
    94 | * 95 | * @param encodedKey encoded byte array 96 | * @return public key 97 | * 98 | * @throws NoSuchAlgorithmException wrong algorithm (should not occur) 99 | * @throws NoSuchProviderException wrong provider (should not occur) 100 | * @throws InvalidKeySpecException invalid key (should not occur) 101 | */ 102 | public static PublicKey getPublic(byte[] encodedKey) 103 | throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { 104 | return getPublic(encodedKey, KPG_ALGORITHM, PROVIDER); 105 | } 106 | 107 | /** 108 | * Returns the public key from the encoded byte array. 109 | * The bytes can be recovered from a Hex string saved in a file etc. 110 | * 111 | * @param encodedKey the encoded public key in bytes. 112 | * @param kpgAlgorithm key pair algorithm 113 | * @param provider provider 114 | * 115 | * @throws NoSuchAlgorithmException wrong algorithm 116 | * @throws NoSuchProviderException wrong provider 117 | * @throws InvalidKeySpecException invalid key (should not occur) 118 | */ 119 | public static PublicKey getPublic(byte[] encodedKey, String kpgAlgorithm, String provider) 120 | throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { 121 | 122 | KeyFactory kf = KeyFactory.getInstance(kpgAlgorithm, provider); 123 | 124 | return kf.generatePublic(new X509EncodedKeySpec(encodedKey)); 125 | } 126 | 127 | /** 128 | * Returns the private key for default arguments from the encoded byte array 129 | * 130 | *
      131 | *
    • key pair algorithm = DSA
    • 132 | *
    • provider = SUN
    • 133 | *
    134 | * 135 | * @param encodedKey encoded byte array 136 | * 137 | * @return private key 138 | * 139 | * @throws NoSuchAlgorithmException 140 | * @throws NoSuchProviderException 141 | * @throws InvalidKeySpecException 142 | */ 143 | public static PrivateKey getPrivate(byte[] encodedKey) 144 | throws InvalidKeySpecException, NoSuchProviderException, NoSuchAlgorithmException { 145 | return getPrivate(encodedKey, KPG_ALGORITHM, PROVIDER); 146 | } 147 | 148 | /** 149 | * This method gets the private key from the encoded byte. 150 | * The bytes can be recovered from a Hex string saved in a file etc. 151 | * @param encodedKey the encoded private key in bytes. 152 | */ 153 | public static PrivateKey getPrivate(byte[] encodedKey, String kpgAlgorithm, String provider) 154 | throws InvalidKeySpecException, NoSuchProviderException, NoSuchAlgorithmException { 155 | 156 | KeyFactory kf = KeyFactory.getInstance(kpgAlgorithm, provider); 157 | 158 | return kf.generatePrivate(new PKCS8EncodedKeySpec(encodedKey)); 159 | } 160 | 161 | /** 162 | * Generates key pair for default arguments 163 | *
      164 | *
    • key length = 1024
    • 165 | *
    • key pair algorithm = DSA
    • 166 | *
    • provider = SUN
    • 167 | *
    • random generator algorithm = SHA1PRNG
    • 168 | *
    169 | * 170 | * @return a new key pair 171 | * 172 | * @throws NoSuchAlgorithmException invalid algorithm 173 | * @throws NoSuchProviderException invalid provider 174 | */ 175 | public static KeyPair getKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException { 176 | return getKeyPair(KEYLEN, KPG_ALGORITHM, PROVIDER, RNG_ALGORITHM); 177 | } 178 | 179 | /** 180 | * Generates the key pair with arguments. 181 | * 182 | * @param keyLen key length 183 | * @param kpgAlgorithm algorithm for key pair generator (DSA, RSA, ...) 184 | * @param provider algorithm provider (SUN, ...) 185 | * @param rngAlgorithm algorithm for random generator (SHA1PRNG, ...) 186 | * @return a new key pair 187 | * 188 | * @throws NoSuchAlgorithmException invalid algorithm 189 | * @throws NoSuchProviderException invalid provider 190 | * 191 | */ 192 | public static KeyPair getKeyPair(int keyLen, String kpgAlgorithm, String provider, String rngAlgorithm) 193 | throws NoSuchAlgorithmException, NoSuchProviderException { 194 | 195 | KeyPairGenerator kpg; 196 | 197 | kpg = KeyPairGenerator.getInstance(kpgAlgorithm, provider); 198 | kpg.initialize(keyLen, SecureRandom.getInstance(rngAlgorithm, provider)); 199 | 200 | return kpg.generateKeyPair(); 201 | } 202 | 203 | /////////////////////////////////////////////////////////////////////////////////////////// 204 | // Signature handling 205 | /////////////////////////////////////////////////////////////////////////////////////////// 206 | 207 | /** 208 | * Validates the license using the signature from the license using the default arguments 209 | * 210 | *
      211 | *
    • signature algorithm = SHA1withDSA
    • 212 | *
    • provider = SUN
    • 213 | *
    214 | * 215 | * @param lic the license. 216 | * @param publicKey public key as a hex string 217 | * @return a boolean whether the license data is valid. 218 | * @throws GeneralSecurityException if any exception was thrown 219 | */ 220 | public static boolean verify(NvAbstractLicense lic, final String publicKey) throws GeneralSecurityException { 221 | return verify(lic, publicKey, SIG_ALGORITHM, PROVIDER); 222 | } 223 | 224 | /** 225 | * Validates the license using the signature from the license. Algorithm and provider 226 | * are passed a arguments 227 | * 228 | * @param lic the license. 229 | * @param publicKey public key as a hex string 230 | * @param sigAlgorithm algorithm for the signature (SHA1withDSA, ...) 231 | * @param provider algorithm provider (SUN, ...) 232 | * @return a boolean whether the license data is valid. 233 | * @throws GeneralSecurityException if any exception was thrown 234 | */ 235 | public static boolean verify(NvAbstractLicense lic, final String publicKey, String sigAlgorithm, String provider) 236 | throws GeneralSecurityException { 237 | 238 | String errMsg = "License verification failed: "; 239 | String signature = lic.getSignature(); 240 | 241 | if ((signature == null) || (signature.trim().length() == 0)) { 242 | throw new GeneralSecurityException(errMsg + "no signature"); 243 | } 244 | 245 | lic.setSignature(null); 246 | 247 | try { 248 | 249 | String json = toJson(lic, false); 250 | byte[] sigArr = ByteHex.convert(signature); 251 | boolean isValid = false; 252 | Signature sig = Signature.getInstance(sigAlgorithm, provider); 253 | PublicKey key = getPublic(ByteHex.convert(publicKey)); 254 | 255 | sig.initVerify(key); 256 | sig.update(json.getBytes()); 257 | isValid = sig.verify(sigArr); 258 | lic.setSignature(signature); 259 | 260 | return isValid; 261 | 262 | } catch (NoSuchAlgorithmException e) { 263 | errMsg += "no such algorithm (" + e.getMessage() + ")"; 264 | } catch (NoSuchProviderException e) { 265 | errMsg += "no such provider (" + e.getMessage() + ")"; 266 | } catch (InvalidKeySpecException e) { 267 | errMsg += "invalid key specification (" + e.getMessage() + ")"; 268 | } catch (InvalidKeyException e) { 269 | errMsg += "invalid key (" + e.getMessage() + ")"; 270 | } catch (SignatureException e) { 271 | errMsg += "signature exception (" + e.getMessage() + ")"; 272 | } catch (IllegalArgumentException e) { 273 | errMsg += "signature not a hex string"; 274 | } 275 | 276 | lic.setSignature(signature); 277 | 278 | throw new GeneralSecurityException(errMsg); 279 | } 280 | 281 | /** 282 | * Signing the license data based on the private key using the default arguments 283 | * 284 | *
      285 | *
    • signature algorithm = SHA1withDSA
    • 286 | *
    • provider = SUN
    • 287 | *
    288 | * 289 | * @param lic the license. 290 | * @param privateKey private key as a hex string 291 | * @return a boolean whether the license data is valid. 292 | * @throws GeneralSecurityException if any exception was thrown 293 | */ 294 | public static void sign(NvAbstractLicense lic, final String privateKey) throws GeneralSecurityException { 295 | sign(lic, privateKey, SIG_ALGORITHM, PROVIDER); 296 | } 297 | 298 | /** 299 | * Signes the license data based on the private key. Algorithm and provider are passed as arguments. 300 | * 301 | * @param lic the license. 302 | * @param privateKey private key as a hex string 303 | * @param sigAlgorithm algorithm for the signature (SHA1withDSA, ...) 304 | * @param provider algorithm provider (SUN, ...) 305 | * 306 | * @param lic the license. 307 | * @throws GeneralSecurityException if any exception was thrown 308 | */ 309 | public static void sign(NvAbstractLicense lic, final String privateKey, String sigAlgorithm, String provider) 310 | throws GeneralSecurityException { 311 | 312 | String errMsg = "License sign failed: "; 313 | 314 | try { 315 | 316 | Signature sig = Signature.getInstance(sigAlgorithm, provider); 317 | PrivateKey key = getPrivate(ByteHex.convert(privateKey)); 318 | String json = toJson(lic, false); 319 | 320 | sig.initSign(key); 321 | sig.update(json.getBytes()); 322 | 323 | byte[] result = sig.sign(); 324 | 325 | lic.setSignature(ByteHex.convert(result)); 326 | 327 | } catch (NoSuchAlgorithmException e) { 328 | throw new GeneralSecurityException(errMsg + "no such algorithm (" + e.getMessage() + ")"); 329 | } catch (NoSuchProviderException e) { 330 | throw new GeneralSecurityException(errMsg + "no such provider (" + e.getMessage() + ")"); 331 | } catch (InvalidKeySpecException e) { 332 | throw new GeneralSecurityException(errMsg + "invalid key specification (" + e.getMessage() + ")"); 333 | } catch (InvalidKeyException e) { 334 | throw new GeneralSecurityException(errMsg + "invalid key (" + e.getMessage() + ")"); 335 | } catch (SignatureException e) { 336 | throw new GeneralSecurityException(errMsg + "signature exception (" + e.getMessage() + ")"); 337 | } catch (IllegalArgumentException e) { 338 | throw new GeneralSecurityException(errMsg + "signature not a hex string"); 339 | } 340 | } 341 | 342 | /////////////////////////////////////////////////////////////////////////////////////////// 343 | // Converting tools 344 | /////////////////////////////////////////////////////////////////////////////////////////// 345 | 346 | /** 347 | * Converts a license Java object to the JSON string with PrettyFormat feature 348 | * 349 | * @param license the license as Java object 350 | * @return the license as JSON string 351 | */ 352 | public static String toJson(NvAbstractLicense license) { 353 | return toJson(license, true); 354 | } 355 | 356 | /** 357 | * Converts a license Java object to the Json string. Using PrettyFormat 358 | * generates better human readable Json string. 359 | * 360 | * @param license the license as Java object 361 | * @param prettyFormat true if output should be pretty formatted 362 | * @return the license as Json string 363 | */ 364 | public static String toJson(NvAbstractLicense license, boolean prettyFormat) { 365 | 366 | SerializeWriter out = new SerializeWriter(); 367 | SerializeConfig config = new SerializeConfig(); 368 | 369 | try { 370 | 371 | JSONSerializer serializer = new JSONSerializer(out, config); 372 | 373 | serializer.config(SerializerFeature.WriteDateUseDateFormat, true); 374 | serializer.config(SerializerFeature.PrettyFormat, prettyFormat); 375 | serializer.setDateFormat(DATE_FORMAT); 376 | 377 | // license.configureSerializer(config); 378 | serializer.write(license); 379 | 380 | return out.toString(); 381 | 382 | } finally { 383 | out.close(); 384 | } 385 | 386 | // return JSON.toJSONStringWithDateFormat(license, "YYYY-MM-dd", features); 387 | } 388 | 389 | /** 390 | * Converts a JSON string to the Java object. The JSON 391 | * must be a serialization of {@link NvAbstractLicense} subclass 392 | * 393 | * @param json a license as JSON object 394 | * @return license as Java object 395 | */ 396 | public static T toObject(String json, Class clazz) 397 | throws IllegalAccessException, InstantiationException { 398 | return toObject(json, clazz, ParserConfig.getGlobalInstance()); 399 | } 400 | 401 | /** 402 | * Converts a JSON string to the Java object. The JSON 403 | * must be a serialization of {@link NvAbstractLicense} subclass 404 | * 405 | * @param json a license as JSON object 406 | * @return license as Java object 407 | */ 408 | public static T toObject(String json, Class clazz, ParserConfig config) 409 | throws IllegalAccessException, InstantiationException { 410 | 411 | T lic = JSON.parseObject(json, clazz); 412 | 413 | /** 414 | * Currently a bug in FastJSON - DefaultJSONParser.parseObject() does not 415 | * accept field annotation @JSONField nd does not install custom 416 | * deserializer. 417 | * 418 | * ! -> lic.beforeDeserialize is not called ! 419 | * 420 | T lic = clazz.newInstance(); 421 | 422 | // lic.configureDeserializer(ParserConfig.getGlobalInstance()); 423 | lic.beforeDeserialize(); 424 | 425 | DefaultJSONParser parser = new DefaultJSONParser(json, config, DEFAULT_PARSER_FEATURE); 426 | parser.parseObject(lic); 427 | parser.close(); 428 | 429 | */ 430 | 431 | lic.afterDeserialize(); 432 | 433 | return lic; 434 | } 435 | 436 | /** 437 | * Writes the license into a file 438 | * 439 | * @param license license object 440 | * @param fileName name of the license file 441 | * @throws IOException error on file write occurred 442 | */ 443 | public static void writeLicense(NvAbstractLicense license, String fileName) throws IOException, GeneralSecurityException { 444 | 445 | if ((license.getSignature() == null) || license.getSignature().isEmpty()) { 446 | throw new GeneralSecurityException("Cannot save a license without signature"); 447 | } 448 | 449 | FileOutputStream file = new FileOutputStream(fileName); 450 | 451 | file.write(LicenseUtils.toJson(license).getBytes()); 452 | file.close(); 453 | } 454 | 455 | /** 456 | * Reads the license from a file 457 | * 458 | * @param fileName name of the license file 459 | * @throws IOException error on file write occurred 460 | */ 461 | public static T readLicense(String fileName, Class clazz) 462 | throws IOException, GeneralSecurityException, InstantiationException, IllegalAccessException { 463 | 464 | String content = new String(Files.readAllBytes(Paths.get(fileName))); 465 | 466 | return toObject(content, clazz); 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/main/java/com/neopsis/envas/util/NvLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)NvLog.java 22.11.09 3 | * 4 | * Copyright (c) 2007-2012 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.util; 12 | 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | /** 17 | * Module logging 18 | * 19 | */ 20 | public class NvLog { 21 | 22 | public static final Logger logger = Logger.getLogger("envasCommons"); 23 | 24 | public static void trace(String message) { 25 | 26 | if (logger.isLoggable(Level.FINE)) { 27 | logger.fine(message); 28 | } 29 | } 30 | 31 | public static void message(String message) { 32 | logger.info(message); 33 | } 34 | 35 | public static void warning(String message) { 36 | logger.warning(message); 37 | } 38 | 39 | public static void error(String message) { 40 | logger.severe(message); 41 | } 42 | 43 | public static void error(String message, Exception ex) { 44 | logger.log(Level.SEVERE, message, ex); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/test/java/com/neopsis/envas/test/TestRunner.java: -------------------------------------------------------------------------------- 1 | package com.neopsis.envas.test; 2 | 3 | public class TestRunner { 4 | 5 | public static void main(String[] args) { 6 | 7 | Tests t = new Tests(); 8 | 9 | t.generateKeyPair(); 10 | t.licensorTest(); 11 | t.licenseeTest(); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /envasCommons/envasCommons-rt/src/test/java/com/neopsis/envas/test/Tests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @(#)Tests.java 13.12.2017 3 | * 4 | * Copyright (c) 2007 Neopsis GmbH 5 | * 6 | * 7 | */ 8 | 9 | 10 | 11 | package com.neopsis.envas.test; 12 | 13 | import com.neopsis.envas.commons.license.NvLicense; 14 | import com.neopsis.envas.commons.license.NvLicenseFeature; 15 | import com.neopsis.envas.commons.license.util.ByteHex; 16 | import com.neopsis.envas.commons.license.util.LicenseUtils; 17 | import org.testng.annotations.Test; 18 | 19 | import javax.baja.license.Feature; 20 | import java.io.IOException; 21 | import java.security.GeneralSecurityException; 22 | import java.security.KeyPair; 23 | import java.security.PrivateKey; 24 | import java.security.PublicKey; 25 | import java.util.Date; 26 | 27 | import static org.junit.Assert.*; 28 | 29 | /** 30 | * Test cases 31 | * 32 | * 33 | * @version 1.0.0, 13.12.2017 34 | * @author Robert Carnecky 35 | */ 36 | public class Tests { 37 | 38 | public static String PRIVATE_KEY = 39 | "3082014C0201003082012C06072A8648CE3804013082011F02818100FD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C70215009760508F15230BCCB292B982A2EB840BF0581CF502818100F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A04170215008DD7783E59BFD923A4BCB79DADEBEFF119BB55C3"; 40 | public static String PUBLIC_KEY = 41 | "308201B73082012C06072A8648CE3804013082011F02818100FD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C70215009760508F15230BCCB292B982A2EB840BF0581CF502818100F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A038184000281806BAD0894CACDF97BF7653C13527D20F6DC30B18A5570AF9FEA7B0D3A6673B68EF710F56FE4E6921DC7B5BAA3C7103E5387BD9C7A8AD412322584D684E9A8BB7CC0384673B9D39218DC933081C247D056D835D557E61DB55B6A49299C0C7C40A8D1779AB434E662986F0CFD935A530528F4B07B32847C43DC8F8537EC1F92CEAB"; 42 | public static String GEN_PRIVATE_KEY; 43 | public static String GEN_PUBLIC_KEY; 44 | public static Date sysdate = new Date(); 45 | public static String VENDOR = "ACME"; 46 | public static Date GENERATED = new Date(sysdate.getYear(), sysdate.getMonth(), sysdate.getDate()); 47 | public static Date EXPIRED = new Date(sysdate.getYear() + 1, sysdate.getMonth(), sysdate.getDate()); 48 | 49 | // feature 1 50 | public static String FEATURE1 = "reports"; 51 | public static String OPTION_KEY11 = "pdf"; 52 | public static String OPTION_KEY12 = "doc"; 53 | public static String OPTION_KEY13 = "html"; 54 | public static String OPTION_VALUE11 = "true"; 55 | public static String OPTION_VALUE12 = "false"; 56 | public static String OPTION_VALUE13 = "true"; 57 | 58 | // feature 2 59 | public static String FEATURE2 = "rdbms"; 60 | public static String OPTION_KEY21 = "type"; 61 | public static String OPTION_KEY22 = "max_tables"; 62 | public static String OPTION_VALUE21 = "mysql"; 63 | public static int OPTION_VALUE22 = 200; 64 | public static String OPTION23 = "html"; 65 | 66 | // 67 | public static String HOST_ID = "Win-0000-1234-ABCD-FFFF"; 68 | public static String VERSION = "1.0"; 69 | public static String FILE_NAME = HOST_ID + ".l4e"; 70 | 71 | /** 72 | * Generates the key pair for the test 73 | */ 74 | @Test 75 | public void generateKeyPair() { 76 | 77 | try { 78 | 79 | KeyPair keyPair = LicenseUtils.getKeyPair(); 80 | PrivateKey privateKey = keyPair.getPrivate(); 81 | PublicKey publicKey = keyPair.getPublic(); 82 | 83 | GEN_PRIVATE_KEY = ByteHex.convert(privateKey.getEncoded()); 84 | GEN_PUBLIC_KEY = ByteHex.convert(publicKey.getEncoded()); 85 | System.out.println("----------------- KEY PAIR ------------------"); 86 | System.out.println("PRIVATE: " + GEN_PRIVATE_KEY); 87 | System.out.println("PUBLIC : " + GEN_PUBLIC_KEY); 88 | System.out.println(); 89 | 90 | } catch (Exception e) { 91 | fail("Cannot generate a key pair"); 92 | } 93 | } 94 | 95 | @Test 96 | public void licensorTest() { 97 | 98 | System.out.println("Licensor test"); 99 | 100 | NvLicense lic = new NvLicense(); 101 | 102 | lic.setVendor(VENDOR); 103 | lic.setExpiration(Long.MAX_VALUE); 104 | lic.setGenerated(GENERATED.getTime()); 105 | lic.setHostId(HOST_ID); 106 | lic.setVersion(VERSION); 107 | 108 | NvLicenseFeature feature1 = new NvLicenseFeature(); 109 | 110 | feature1.setVendorName(VENDOR); 111 | feature1.setFeatureName(FEATURE1); 112 | feature1.setExpiration(EXPIRED.getTime()); 113 | feature1.addOption(OPTION_KEY11, OPTION_VALUE11); 114 | feature1.addOption(OPTION_KEY12, OPTION_VALUE12); 115 | feature1.addOption(OPTION_KEY13, OPTION_VALUE13); 116 | lic.addFeature(feature1); 117 | 118 | NvLicenseFeature feature2 = new NvLicenseFeature(); 119 | 120 | feature2.setVendorName(VENDOR); 121 | feature2.setFeatureName(FEATURE2); 122 | feature2.setExpiration(Long.MAX_VALUE); 123 | feature2.addOption(OPTION_KEY21, OPTION_VALUE21); 124 | feature2.addOption(OPTION_KEY22, OPTION_VALUE22); 125 | lic.addFeature(feature2); 126 | 127 | try { 128 | LicenseUtils.sign(lic, PRIVATE_KEY); 129 | } catch (GeneralSecurityException e) { 130 | fail("cannot sign the license"); 131 | } 132 | 133 | assertNotNull(lic.getSignature()); 134 | 135 | Feature f = lic.getFeature(FEATURE1); 136 | 137 | assertNotNull("Cannot get license feature", f); 138 | assertTrue(f.getExpiration() == EXPIRED.getTime()); 139 | assertTrue("Feature vendor missing", f.getVendorName().equalsIgnoreCase(VENDOR)); 140 | 141 | // TEST: write the license to a file 142 | try { 143 | LicenseUtils.writeLicense(lic, FILE_NAME); 144 | } catch (Exception e) { 145 | fail("Cannot wrote the license to the file " + FILE_NAME + "(" + e.getMessage() + ")"); 146 | } 147 | } 148 | 149 | @Test 150 | public void licenseeTest() { 151 | 152 | System.out.println("Licensee test"); 153 | 154 | NvLicense lic = null; 155 | boolean isValid = false; 156 | 157 | // TEST: read the license from the file 158 | try { 159 | lic = LicenseUtils.readLicense(FILE_NAME, NvLicense.class); 160 | } catch (IOException e) { 161 | fail("IOException when reading file (" + e.getMessage() + ")"); 162 | } catch (GeneralSecurityException e) { 163 | fail("GeneralSecurityException when reading file (" + e.getMessage() + ")"); 164 | } catch (InstantiationException e) { 165 | fail("InstantiationException when reading file (" + e.getMessage() + ")"); 166 | } catch (IllegalAccessException e) { 167 | fail("IllegalAccessException when reading file (" + e.getMessage() + ")"); 168 | } 169 | 170 | try { 171 | isValid = lic.verify(PUBLIC_KEY); 172 | } catch (GeneralSecurityException e) { 173 | fail("GeneralSecurityException when verifying license: " + e.getMessage() ); 174 | } 175 | 176 | assertTrue("Valid license failed the verification", isValid); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: global settings in %USER_HOME%/.gradle/gradle.setting have higher priority 3 | # and override settings from this file! 4 | # 5 | # niagara_home=C:/Niagara/Niagara-4.13.0.186 6 | # niagara_user_home=C:/Users/robert/Niagara4.13 7 | # systemProp.neopsisPluginVersion=1.0.0 8 | 9 | build_release = 10 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neopsis/envas-commons/16f871200a169d98fd21f957c0dc4332ad45c826/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Neopsis GmbH. All Rights Reserved. 3 | * 4 | */ 5 | 6 | pluginManagement { 7 | 8 | val neopsisPluginVersion: String by System.getProperties() 9 | 10 | repositories { 11 | 12 | maven(url = providers.gradleProperty("niagaraToolsHome").get() + "/gradlePlugins") 13 | maven(url = uri("https://repo.repsy.io/mvn/neopsis/niagara")) 14 | mavenCentral() 15 | // mavenLocal() 16 | gradlePluginPortal() 17 | 18 | } 19 | 20 | plugins { 21 | id("com.neopsis.niagara-settings-plugin") version (neopsisPluginVersion) 22 | id("com.neopsis.niagara-project-plugin") version (neopsisPluginVersion) 23 | id("com.neopsis.niagara-module-plugin") version (neopsisPluginVersion) 24 | } 25 | } 26 | 27 | plugins { 28 | id("com.neopsis.niagara-settings-plugin") 29 | } 30 | 31 | rootProject.name = "envasCommons" --------------------------------------------------------------------------------