-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added new entity MailStatementProfile to store setup of fetching stat…
…ements from mail Updated Manage Transaction Dashboard to show mail statement profile Adapted action 'Fetch from Mail' to select MailStatementProfile instead of providing all the details Minor changes in TransactionReaderCallback to consider sourceId while looking for existing transaction
- Loading branch information
Showing
13 changed files
with
681 additions
and
53 deletions.
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
...ources/db/migration/hsqldb/V0_1_0_0_5__MailConnectionProfile_increase_password_length.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- increase length of password column from 40 to 1024 | ||
ALTER TABLE "statements"."MailConnectionProfile" ALTER COLUMN "password" VARCHAR(1024); |
11 changes: 11 additions & 0 deletions
11
...n/src/main/resources/db/migration/hsqldb/V0_1_0_0_6__Added_MailStatementProfile_table.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
CREATE TABLE "statements"."MailStatementProfile"("id" BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL,"fileNamePattern" VARCHAR(128) NOT NULL, "fromAddress" VARCHAR(255), "subjectWords" VARCHAR(255) NOT NULL,"folderName" VARCHAR(255) NOT NULL,"readerId" BIGINT NOT NULL, "sourceId" BIGINT NOT NULL, "mailConnectionProfileId" BIGINT NOT NULL,"description" VARCHAR(4000),"name" VARCHAR(40) NOT NULL,"version" TIMESTAMP NOT NULL,CONSTRAINT "MailStatementProfile_PK" PRIMARY KEY("id"),CONSTRAINT "MailStatementProfile_name_UNQ" UNIQUE("name")); | ||
ALTER TABLE "statements"."MailStatementProfile" ALTER COLUMN "id" RESTART WITH 0; | ||
|
||
CREATE INDEX "MailStatementProfile_N51" ON "statements"."MailStatementProfile"("sourceId"); | ||
CREATE INDEX "MailStatementProfile_N50" ON "statements"."MailStatementProfile"("readerId"); | ||
CREATE INDEX "MailStatementProfile_N49" ON "statements"."MailStatementProfile"("mailConnectionProfileId"); | ||
|
||
ALTER TABLE "statements"."MailStatementProfile" ADD CONSTRAINT "MailStatementProfile_FK3" FOREIGN KEY("mailConnectionProfileId") REFERENCES "statements"."MailConnectionProfile"("id"); | ||
ALTER TABLE "statements"."MailStatementProfile" ADD CONSTRAINT "MailStatementProfile_FK2" FOREIGN KEY("readerId") REFERENCES "statements"."StatementReader"("id"); | ||
ALTER TABLE "statements"."MailStatementProfile" ADD CONSTRAINT "MailStatementProfile_FK1" FOREIGN KEY("sourceId") REFERENCES "statements"."StatementSource"("id"); |
219 changes: 219 additions & 0 deletions
219
module-base/src/main/java/domainapp/modules/base/service/EncryptionService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
/** | ||
* | ||
*/ | ||
package domainapp.modules.base.service; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.StandardOpenOption; | ||
import java.security.InvalidKeyException; | ||
import java.security.KeyFactory; | ||
import java.security.KeyPair; | ||
import java.security.KeyPairGenerator; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.PrivateKey; | ||
import java.security.PublicKey; | ||
import java.security.spec.InvalidKeySpecException; | ||
import java.security.spec.PKCS8EncodedKeySpec; | ||
import java.security.spec.X509EncodedKeySpec; | ||
import java.util.ArrayList; | ||
import java.util.Base64; | ||
import java.util.List; | ||
|
||
import javax.annotation.PostConstruct; | ||
import javax.annotation.PreDestroy; | ||
import javax.crypto.BadPaddingException; | ||
import javax.crypto.Cipher; | ||
import javax.crypto.IllegalBlockSizeException; | ||
import javax.crypto.NoSuchPaddingException; | ||
import javax.inject.Inject; | ||
|
||
import org.apache.isis.applib.annotation.DomainService; | ||
import org.apache.isis.applib.annotation.NatureOfService; | ||
import org.apache.isis.applib.annotation.Programmatic; | ||
import org.apache.isis.applib.services.config.ConfigurationService; | ||
|
||
import com.google.gson.Gson; | ||
import com.google.gson.GsonBuilder; | ||
|
||
/** | ||
* @author jayeshecs | ||
* Ref: https://stackoverflow.com/questions/24338108/java-encrypt-string-with-existing-public-key-file | ||
*/ | ||
@DomainService( | ||
nature = NatureOfService.DOMAIN | ||
) | ||
public class EncryptionService { | ||
|
||
private static final String ALGO_RSA = "RSA"; | ||
private PublicKey publicKey; | ||
private PrivateKey privateKey; | ||
|
||
public EncryptionService() { | ||
// DO NOTHING | ||
} | ||
|
||
@PostConstruct | ||
public void init() { | ||
String keyLocation = configurationService.getProperty("base.kl", System.getProperty("user.home") + "/.ssh"); | ||
File keyLocationFile = new File(keyLocation); | ||
if (!keyLocationFile.exists()) { | ||
throw new IllegalArgumentException("Location '" + keyLocation + "' does not exists"); | ||
} | ||
if (!keyLocationFile.isDirectory()) { | ||
throw new IllegalArgumentException("Location '" + keyLocation + "' must be a valid directory"); | ||
} | ||
if (!keyLocationFile.canWrite() || !keyLocationFile.canExecute() || !keyLocationFile.canRead()) { | ||
throw new IllegalArgumentException("Location '" + keyLocation + "' must have read/write/execute permission"); | ||
} | ||
File file = new File(keyLocationFile, ".dmbse"); // key file name | ||
|
||
if (!file.exists()) { | ||
KeyPair keyPair = generateKeyPair(); | ||
saveGeneratedKeys(file, keyPair); | ||
} | ||
|
||
List<String> encodedKeys = loadEncodedKeys(file); | ||
publicKey = loadPublicKeyFromEncodedKeys(encodedKeys); | ||
privateKey = loadPrivateKeyFromEncodedKeys(encodedKeys); | ||
} | ||
|
||
@Programmatic | ||
private PublicKey loadPublicKeyFromEncodedKeys(List<String> encodedKeys) { | ||
try { | ||
/* Generate public key. */ | ||
X509EncodedKeySpec ks = new X509EncodedKeySpec(Base64.getDecoder().decode(encodedKeys.get(0).getBytes())); | ||
KeyFactory kf = KeyFactory.getInstance(ALGO_RSA); | ||
PublicKey pub = kf.generatePublic(ks); | ||
return pub; | ||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) { | ||
throw new IllegalStateException("Error occurred while loading public key from encoded keys", e); | ||
} | ||
} | ||
|
||
@Programmatic | ||
private PrivateKey loadPrivateKeyFromEncodedKeys(List<String> encodedKeys) { | ||
try { | ||
/* Generate private key. */ | ||
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(encodedKeys.get(1).getBytes())); | ||
KeyFactory kf = KeyFactory.getInstance(ALGO_RSA); | ||
PrivateKey privateKey = kf.generatePrivate(ks); | ||
return privateKey; | ||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) { | ||
throw new IllegalStateException("Error occurred while loading private key from encoded keys", e); | ||
} | ||
} | ||
|
||
@Programmatic | ||
private List<String> loadEncodedKeys(File file) { | ||
try { | ||
byte[] bytes = Files.readAllBytes(file.toPath()); | ||
byte[] decodedBytes = Base64.getDecoder().decode(bytes); | ||
Gson gson = new GsonBuilder().create(); | ||
@SuppressWarnings("unchecked") | ||
List<String> encodedKeys = gson.fromJson(new String(decodedBytes), List.class); | ||
return encodedKeys; | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Error occurred while loading encoded keys from file - " + file); | ||
} | ||
} | ||
|
||
/** | ||
* @param file | ||
* @param publicKey | ||
* @param privateKey | ||
*/ | ||
@Programmatic | ||
private void saveGeneratedKeys(File file, KeyPair keyPair) { | ||
// encode key pair | ||
String encodedKeyPair = encodeKeyPair(keyPair); | ||
// save encodedKeyPair | ||
saveEncodedKeyPair(file, encodedKeyPair); | ||
} | ||
|
||
/** | ||
* @param keyPair | ||
* @return | ||
*/ | ||
@Programmatic | ||
private String encodeKeyPair(KeyPair keyPair) { | ||
PublicKey publicKey = keyPair.getPublic(); | ||
PrivateKey privateKey = keyPair.getPrivate(); | ||
// get encoded keys | ||
String encodedPublicKey = new String(Base64.getEncoder().encode(publicKey.getEncoded())); | ||
String encodedPrivateKey = new String(Base64.getEncoder().encode(privateKey.getEncoded())); | ||
// prepare list of encoded keys | ||
List<String> keys = new ArrayList<String>(); | ||
keys.add(encodedPublicKey); | ||
keys.add(encodedPrivateKey); | ||
// convert keys list to JSON | ||
Gson gson = new GsonBuilder().create(); | ||
String json = gson.toJson(keys); | ||
// decode json string using Base64 | ||
String encodedKeyPair = Base64.getEncoder().encodeToString(json.getBytes()); | ||
return encodedKeyPair; | ||
} | ||
|
||
/** | ||
* @param file | ||
* @param encodedKeyPair | ||
*/ | ||
@Programmatic | ||
private void saveEncodedKeyPair(File file, String encodedKeyPair) { | ||
try { | ||
Files.write(file.toPath(), encodedKeyPair.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Error occurred while saving generated key pair"); | ||
} | ||
} | ||
|
||
/** | ||
* @return | ||
*/ | ||
@Programmatic | ||
private KeyPair generateKeyPair() { | ||
try { | ||
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(ALGO_RSA); | ||
keyGenerator.initialize(2048); | ||
KeyPair keyPair = keyGenerator.generateKeyPair(); | ||
return keyPair; | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new IllegalStateException("Error occurred while generating key pair"); | ||
} | ||
} | ||
|
||
@PreDestroy | ||
public void destroy() { | ||
privateKey = null; | ||
publicKey = null; | ||
} | ||
|
||
@Programmatic | ||
public String encrypt(String content) { | ||
try { | ||
Cipher instance = Cipher.getInstance(ALGO_RSA); | ||
instance.init(Cipher.ENCRYPT_MODE, publicKey); | ||
byte[] encrypted = instance.doFinal(content.getBytes()); | ||
byte[] encoded = Base64.getEncoder().encode(encrypted); | ||
return new String(encoded); | ||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) { | ||
throw new IllegalStateException("Error occurred while encrypting given content using public key", e); | ||
} | ||
} | ||
|
||
public String decrypt(String encryptedContent) { | ||
try { | ||
Cipher instance = Cipher.getInstance(ALGO_RSA); | ||
instance.init(Cipher.DECRYPT_MODE, privateKey); | ||
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedContent.getBytes()); | ||
byte[] decrypted = instance.doFinal(encryptedBytes); | ||
return new String(decrypted); | ||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) { | ||
throw new IllegalStateException("Error occurred while decrypting given content using private key", e); | ||
} | ||
} | ||
|
||
@Inject | ||
protected ConfigurationService configurationService; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.