mirror of
https://github.com/moparisthebest/mailiverse
synced 2024-11-24 01:22:16 -05:00
adds a set of files
This commit is contained in:
parent
b0c64f9d08
commit
10028cd6e8
10
License.txt
Normal file
10
License.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Portions of this code are release GPL and portions are released BSD.
|
||||||
|
|
||||||
|
Anything to do with the web is GPLv3 Affero + keep my name in the code.
|
||||||
|
Anything to do with the iPhone is BSD + keep my name in the code.
|
||||||
|
Anything to do with the Android is GPLv3 Affero + keep my name in the code.
|
||||||
|
|
||||||
|
License documentation will be placed in each file accordingly.
|
||||||
|
|
||||||
|
|
||||||
|
If you need a different license, please contact me.
|
40
java/core/src/core/crypt/Cryptor.java
Normal file
40
java/core/src/core/crypt/Cryptor.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public abstract class Cryptor
|
||||||
|
{
|
||||||
|
static final boolean TEST_ENCRYPTION = false;
|
||||||
|
|
||||||
|
abstract public byte[] encrypt (byte[] bytes) throws CryptoException;
|
||||||
|
abstract public byte[] decrypt (byte[] bytes) throws CryptoException;
|
||||||
|
|
||||||
|
public Callback encrypt_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Cryptor.this.encrypt((byte[])arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback decrypt_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Cryptor.this.decrypt((byte[])arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
105
java/core/src/core/crypt/CryptorAES.java
Normal file
105
java/core/src/core/crypt/CryptorAES.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.util.Arrays;
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.LogOut;
|
||||||
|
import core.util.SecureRandom;
|
||||||
|
|
||||||
|
public class CryptorAES extends Cryptor
|
||||||
|
{
|
||||||
|
static LogNull log = new LogNull(CryptorAES.class);
|
||||||
|
|
||||||
|
public static final int AES_KEYSIZE_BYTES = 32;
|
||||||
|
public static final int AES_IVSIZE_BYTES = 16;
|
||||||
|
static SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
byte[] key;
|
||||||
|
|
||||||
|
public CryptorAES (byte[] key)
|
||||||
|
{
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final byte[] NullIV = {
|
||||||
|
0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0
|
||||||
|
} ;
|
||||||
|
|
||||||
|
public static byte[] newIV()
|
||||||
|
{
|
||||||
|
byte[] iv = new byte[AES_IVSIZE_BYTES];
|
||||||
|
random.nextBytes(iv);
|
||||||
|
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] newKey()
|
||||||
|
{
|
||||||
|
byte[] key = new byte[AES_KEYSIZE_BYTES];
|
||||||
|
random.nextBytes(key);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
byte[] iv = newIV();
|
||||||
|
Cryptor cryptor = new CryptorAESIV(key, iv);
|
||||||
|
return Arrays.concat(iv, cryptor.encrypt(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] decrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
byte[] iv = Arrays.copyOf(bytes, 0, AES_IVSIZE_BYTES);
|
||||||
|
byte[] data = Arrays.copyOf(bytes, AES_IVSIZE_BYTES, bytes.length - AES_IVSIZE_BYTES);
|
||||||
|
|
||||||
|
Cryptor cryptor = new CryptorAESIV(key, iv);
|
||||||
|
return cryptor.decrypt(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback decrypt_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
byte[] bytes = (byte[]) arguments[0];
|
||||||
|
byte[] iv = Arrays.copyOf(bytes, 0, AES_IVSIZE_BYTES);
|
||||||
|
byte[] data = Arrays.copyOf(bytes, AES_IVSIZE_BYTES, bytes.length - AES_IVSIZE_BYTES);
|
||||||
|
|
||||||
|
log.debug("decrypt_", bytes.length, iv.length, data.length);
|
||||||
|
|
||||||
|
Cryptor cryptor = new CryptorAESIV(key, iv);
|
||||||
|
call(cryptor.decrypt_(), data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback encrypt_()
|
||||||
|
{
|
||||||
|
byte[] iv = newIV();
|
||||||
|
Cryptor cryptor = new CryptorAESIV(key, iv);
|
||||||
|
|
||||||
|
return
|
||||||
|
cryptor.encrypt_()
|
||||||
|
.addCallback(new CallbackDefault(iv) {
|
||||||
|
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
byte[] iv = V(0);
|
||||||
|
byte[] data = (byte[]) arguments[0];
|
||||||
|
log.debug("encrypt_", iv.length, data.length);
|
||||||
|
|
||||||
|
next(Arrays.concat(iv, data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
java/core/src/core/crypt/CryptorAESIV.java
Normal file
93
java/core/src/core/crypt/CryptorAESIV.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.util.Arrays;
|
||||||
|
import core.util.SecureRandom;
|
||||||
|
|
||||||
|
import org.bc.crypto.BufferedBlockCipher;
|
||||||
|
import org.bc.crypto.engines.AESEngine;
|
||||||
|
import org.bc.crypto.modes.CBCBlockCipher;
|
||||||
|
import org.bc.crypto.paddings.BlockCipherPadding;
|
||||||
|
import org.bc.crypto.paddings.PKCS7Padding;
|
||||||
|
import org.bc.crypto.paddings.PaddedBufferedBlockCipher;
|
||||||
|
import org.bc.crypto.params.KeyParameter;
|
||||||
|
import org.bc.crypto.params.ParametersWithIV;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
|
||||||
|
public class CryptorAESIV extends Cryptor
|
||||||
|
{
|
||||||
|
static SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
byte[] key;
|
||||||
|
byte[] iv;
|
||||||
|
|
||||||
|
public CryptorAESIV (byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
// setup cipher parameters with key and IV
|
||||||
|
this.key = key;
|
||||||
|
this.iv = iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] decrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BlockCipherPadding padding = new PKCS7Padding();
|
||||||
|
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
|
||||||
|
new CBCBlockCipher(new AESEngine()), padding);
|
||||||
|
|
||||||
|
ParametersWithIV params = new ParametersWithIV(new KeyParameter(key), iv);
|
||||||
|
cipher.reset();
|
||||||
|
cipher.init(false, params);
|
||||||
|
|
||||||
|
byte[] out = new byte[cipher.getOutputSize(bytes.length)];
|
||||||
|
int len = cipher.processBytes(bytes, 0, bytes.length, out, 0);
|
||||||
|
len += cipher.doFinal(out, len);
|
||||||
|
|
||||||
|
if (len == out.length)
|
||||||
|
return out;
|
||||||
|
|
||||||
|
return Arrays.copyOf(out, len);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BlockCipherPadding padding = new PKCS7Padding();
|
||||||
|
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
|
||||||
|
new CBCBlockCipher(new AESEngine()), padding);
|
||||||
|
|
||||||
|
ParametersWithIV params = new ParametersWithIV(new KeyParameter(key), iv);
|
||||||
|
cipher.reset();
|
||||||
|
cipher.init(true, params);
|
||||||
|
|
||||||
|
byte[] out = new byte[cipher.getOutputSize(bytes.length)];
|
||||||
|
int len = cipher.processBytes(bytes, 0, bytes.length, out, 0);
|
||||||
|
len += cipher.doFinal(out, len);
|
||||||
|
|
||||||
|
if (len == out.length)
|
||||||
|
return out;
|
||||||
|
|
||||||
|
return Arrays.copyOf(out, len);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
java/core/src/core/crypt/CryptorAESJCE.java
Normal file
53
java/core/src/core/crypt/CryptorAESJCE.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
|
||||||
|
public class CryptorAESJCE extends Cryptor
|
||||||
|
{
|
||||||
|
SecretKeySpec secretKey;
|
||||||
|
IvParameterSpec iv;
|
||||||
|
|
||||||
|
public CryptorAESJCE (SecretKeySpec secretKey, IvParameterSpec iv)
|
||||||
|
{
|
||||||
|
this.secretKey = secretKey;
|
||||||
|
this.iv = iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt(byte[] clearText) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
||||||
|
return cipher.doFinal(clearText);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt(byte[] encrypted) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
|
||||||
|
return cipher.doFinal(encrypted);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
java/core/src/core/crypt/CryptorNone.java
Normal file
25
java/core/src/core/crypt/CryptorNone.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class CryptorNone extends Cryptor
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] decrypt(byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
java/core/src/core/crypt/CryptorRSA.java
Normal file
27
java/core/src/core/crypt/CryptorRSA.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
public abstract class CryptorRSA extends Cryptor
|
||||||
|
{
|
||||||
|
byte[] publicKeyBytes, privateKeyBytes;
|
||||||
|
|
||||||
|
public byte[] getPublicKey ()
|
||||||
|
{
|
||||||
|
return publicKeyBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPrivateKey ()
|
||||||
|
{
|
||||||
|
return privateKeyBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initialize (byte[] publicKeyBytes, byte[] privateKeyBytes)
|
||||||
|
{
|
||||||
|
this.privateKeyBytes = privateKeyBytes;
|
||||||
|
this.publicKeyBytes = publicKeyBytes;
|
||||||
|
}
|
||||||
|
}
|
216
java/core/src/core/crypt/CryptorRSAAES.java
Normal file
216
java/core/src/core/crypt/CryptorRSAAES.java
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.LogOut;
|
||||||
|
import core.util.Streams;
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.callback.CallbackSync;
|
||||||
|
import core.callbacks.Memory;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class CryptorRSAAES extends Cryptor
|
||||||
|
{
|
||||||
|
static LogNull log = new LogNull(CryptorRSAAES.class);
|
||||||
|
|
||||||
|
CryptorRSA rsa;
|
||||||
|
|
||||||
|
public static class Version {
|
||||||
|
public static final int
|
||||||
|
R2012 = 0x00,
|
||||||
|
R201303 = 0x01,
|
||||||
|
CURRENT = R201303;
|
||||||
|
};
|
||||||
|
|
||||||
|
public final byte INITIAL = 0x00;
|
||||||
|
public final byte VERSION = 0x01;
|
||||||
|
public final int MAX_RSA_BLOCK_SIZE = 117;
|
||||||
|
|
||||||
|
private final static String M_VERSION = "version";
|
||||||
|
|
||||||
|
public CryptorRSAAES(CryptorRSA rsa)
|
||||||
|
{
|
||||||
|
this.rsa = rsa;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readVersion (InputStream is, Memory memory) throws Exception
|
||||||
|
{
|
||||||
|
int version = is.read()&0xFF;
|
||||||
|
if (version < 0 || version > Version.CURRENT)
|
||||||
|
throw new Exception("Unknown version");
|
||||||
|
|
||||||
|
memory.put(M_VERSION, version);
|
||||||
|
|
||||||
|
log.debug("readVersion", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeVersion (OutputStream os) throws IOException
|
||||||
|
{
|
||||||
|
os.write(Version.CURRENT);
|
||||||
|
|
||||||
|
log.debug("writeVersion", Version.CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback readEncryptedEmbeddedKey_ (InputStream is, Memory memory)
|
||||||
|
{
|
||||||
|
return new CallbackDefault(memory, is) {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
Memory memory = V(0);
|
||||||
|
InputStream is = V(1);
|
||||||
|
|
||||||
|
int version = (Integer)memory.get(M_VERSION);
|
||||||
|
switch (version) {
|
||||||
|
|
||||||
|
case Version.R2012:
|
||||||
|
Streams.readInt3(is); // ignore the wrapper
|
||||||
|
next(Streams.readBoundedArray(is));
|
||||||
|
break;
|
||||||
|
case Version.R201303:
|
||||||
|
next(Streams.readBoundedArray(is));
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback writeEncryptedEmbeddedKey_ (OutputStream os)
|
||||||
|
{
|
||||||
|
return new CallbackDefault(os) {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
OutputStream os = V(0);
|
||||||
|
byte[] bytes = (byte[]) arguments[0];
|
||||||
|
Streams.writeBoundedArray(os, bytes);
|
||||||
|
next(arguments);
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback decryptMainBlock_(InputStream is, Memory memory)
|
||||||
|
{
|
||||||
|
return new CallbackDefault (is, memory) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
InputStream is = V(0);
|
||||||
|
Memory memory = V(1);
|
||||||
|
|
||||||
|
byte[] key = (byte[]) arguments[0];
|
||||||
|
int version = (Integer)memory.get(M_VERSION);
|
||||||
|
|
||||||
|
Cryptor cryptor = null;
|
||||||
|
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case Version.R2012:
|
||||||
|
cryptor = new CryptorAESIV(key, CryptorAES.NullIV);
|
||||||
|
break;
|
||||||
|
case Version.R201303:
|
||||||
|
cryptor = new CryptorAES(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
call(cryptor.decrypt_(), Streams.readFullyBytes(is));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback encryptMainBlock_ (OutputStream os, Cryptor cryptor, byte[] bytes)
|
||||||
|
{
|
||||||
|
return new CallbackDefault (os, cryptor, bytes) {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
OutputStream os = V(0);
|
||||||
|
Cryptor cryptor = V(1);
|
||||||
|
byte[] bytes = V(2);
|
||||||
|
|
||||||
|
call(cryptor.encrypt_().addCallback(Streams.writeBytes_(os)), bytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback decrypt_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault () {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayInputStream is = new ByteArrayInputStream((byte[])arguments[0]);
|
||||||
|
Memory memory = new Memory();
|
||||||
|
readVersion(is, memory);
|
||||||
|
|
||||||
|
call(
|
||||||
|
readEncryptedEmbeddedKey_(is, memory)
|
||||||
|
.addCallback(rsa.decrypt_())
|
||||||
|
.addCallback(decryptMainBlock_(is, memory))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback encrypt_ ()
|
||||||
|
{
|
||||||
|
return new CallbackDefault () {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
writeVersion(os);
|
||||||
|
|
||||||
|
byte[] key = CryptorAES.newKey();
|
||||||
|
CryptorAES aes = new CryptorAES(key);
|
||||||
|
|
||||||
|
call(
|
||||||
|
rsa.encrypt_()
|
||||||
|
.addCallback(writeEncryptedEmbeddedKey_(os))
|
||||||
|
.addCallback(encryptMainBlock_(os, aes, (byte[])arguments[0]))
|
||||||
|
.addCallback(Streams.toByteArray_(os)),
|
||||||
|
key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt (byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new CallbackSync<byte[]>(encrypt_()).invoke(bytes).export();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public byte[] decrypt (byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new CallbackSync<byte[]>(decrypt_()).invoke(bytes).export();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
172
java/core/src/core/crypt/CryptorRSABC.java
Normal file
172
java/core/src/core/crypt/CryptorRSABC.java
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import org.bc.asn1.ASN1InputStream;
|
||||||
|
import org.bc.asn1.ASN1Integer;
|
||||||
|
import org.bc.asn1.ASN1ObjectIdentifier;
|
||||||
|
import org.bc.asn1.ASN1OctetString;
|
||||||
|
import org.bc.asn1.ASN1Primitive;
|
||||||
|
import org.bc.asn1.ASN1Sequence;
|
||||||
|
import org.bc.asn1.DERBitString;
|
||||||
|
import org.bc.asn1.pkcs.RSAPrivateKey;
|
||||||
|
import org.bc.asn1.pkcs.RSAPublicKey;
|
||||||
|
import org.bc.crypto.encodings.PKCS1Encoding;
|
||||||
|
import org.bc.crypto.engines.RSAEngine;
|
||||||
|
import org.bc.crypto.params.RSAKeyParameters;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
public class CryptorRSABC extends CryptorRSA
|
||||||
|
{
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
public final int MAX_RSA_BLOCK_SIZE = 117;
|
||||||
|
|
||||||
|
RSAPublicKey publicKey;
|
||||||
|
RSAPrivateKey privateKey;
|
||||||
|
|
||||||
|
public static final byte[] iv = Arrays.generate(16, 0);
|
||||||
|
|
||||||
|
public CryptorRSABC (byte[] publicKey, byte[] privateKey) throws CryptoException
|
||||||
|
{
|
||||||
|
initialize(publicKey, privateKey);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (privateKey != null)
|
||||||
|
{
|
||||||
|
ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(privateKey));
|
||||||
|
ASN1Primitive keyObject = asn1InputStream.readObject();
|
||||||
|
asn1InputStream.close();
|
||||||
|
|
||||||
|
ASN1Sequence keySequence = (ASN1Sequence)keyObject;
|
||||||
|
ASN1Integer pkcs8Version = (ASN1Integer) keySequence.getObjectAt(0);
|
||||||
|
ASN1Sequence algorithmSequence = (ASN1Sequence) keySequence.getObjectAt(1);
|
||||||
|
ASN1ObjectIdentifier algorithmIdentifier = (ASN1ObjectIdentifier) algorithmSequence.getObjectAt(0);
|
||||||
|
|
||||||
|
String algorithm = algorithmIdentifier.getId();
|
||||||
|
if (!algorithm.equals("1.2.840.113549.1.1.1"))
|
||||||
|
throw new CryptoException("Unknown RSA algorithm");
|
||||||
|
|
||||||
|
ASN1OctetString privateKeyOctets = (ASN1OctetString) keySequence.getObjectAt(2);
|
||||||
|
|
||||||
|
ASN1InputStream asn1PrivateKeyStream = new ASN1InputStream(privateKeyOctets.getOctetStream());
|
||||||
|
ASN1Primitive privateKeyObject = asn1PrivateKeyStream.readObject();
|
||||||
|
asn1PrivateKeyStream.close();
|
||||||
|
ASN1Sequence privateKeySequence = (ASN1Sequence)privateKeyObject;
|
||||||
|
|
||||||
|
int I=0;
|
||||||
|
ASN1Integer
|
||||||
|
s = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
n = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
e = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
d = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
p = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
q = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
d1 = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
d2 = (ASN1Integer)privateKeySequence.getObjectAt(I++),
|
||||||
|
c = (ASN1Integer)privateKeySequence.getObjectAt(I++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/*
|
||||||
|
org.bouncycastle.asn1.pkcs.RSAPrivateKey.RSAPrivateKey(
|
||||||
|
BigInteger modulus,
|
||||||
|
BigInteger publicExponent,
|
||||||
|
BigInteger privateExponent,
|
||||||
|
BigInteger prime1,
|
||||||
|
BigInteger prime2,
|
||||||
|
BigInteger exponent1,
|
||||||
|
BigInteger exponent2,
|
||||||
|
BigInteger coefficient
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
this.privateKey =
|
||||||
|
new RSAPrivateKey(
|
||||||
|
n.getValue(),
|
||||||
|
e.getValue(),
|
||||||
|
d.getValue(),
|
||||||
|
p.getValue(),
|
||||||
|
q.getValue(),
|
||||||
|
d1.getValue(),
|
||||||
|
d2.getValue(),
|
||||||
|
c.getValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicKey != null)
|
||||||
|
{
|
||||||
|
ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(publicKey));
|
||||||
|
ASN1Primitive keyObject = asn1InputStream.readObject();
|
||||||
|
asn1InputStream.close();
|
||||||
|
|
||||||
|
ASN1Sequence keySequence = (ASN1Sequence)keyObject;
|
||||||
|
ASN1Sequence algorithmSequence = (ASN1Sequence) keySequence.getObjectAt(0);
|
||||||
|
ASN1ObjectIdentifier algorithmIdentifier = (ASN1ObjectIdentifier) algorithmSequence.getObjectAt(0);
|
||||||
|
|
||||||
|
String algorithm = algorithmIdentifier.getId();
|
||||||
|
if (!algorithm.equals("1.2.840.113549.1.1.1"))
|
||||||
|
throw new CryptoException("Unknown RSA algorithm");
|
||||||
|
|
||||||
|
DERBitString keyOctets = (DERBitString) keySequence.getObjectAt(1);
|
||||||
|
ASN1InputStream asn1PublicKeyStream = new ASN1InputStream(new ByteArrayInputStream(keyOctets.getBytes()));
|
||||||
|
ASN1Primitive publicKeyObject = asn1PublicKeyStream.readObject();
|
||||||
|
asn1PublicKeyStream.close();
|
||||||
|
|
||||||
|
ASN1Sequence publicKeySequence = (ASN1Sequence)publicKeyObject;
|
||||||
|
|
||||||
|
int I=0;
|
||||||
|
ASN1Integer
|
||||||
|
n = (ASN1Integer)publicKeySequence.getObjectAt(I++),
|
||||||
|
e = (ASN1Integer)publicKeySequence.getObjectAt(I++);
|
||||||
|
|
||||||
|
this.publicKey = new RSAPublicKey(n.getValue(), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt (byte[] block) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PKCS1Encoding e = new PKCS1Encoding(new RSAEngine());
|
||||||
|
RSAKeyParameters key = new RSAKeyParameters(false, publicKey.getModulus(), publicKey.getPublicExponent());
|
||||||
|
e.init(true, key);
|
||||||
|
|
||||||
|
return e.processBlock(block, 0, block.length);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt (byte[] block) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PKCS1Encoding e = new PKCS1Encoding(new RSAEngine());
|
||||||
|
RSAKeyParameters key = new RSAKeyParameters(false, privateKey.getModulus(), privateKey.getPrivateExponent());
|
||||||
|
e.init(false, key);
|
||||||
|
|
||||||
|
return e.processBlock(block, 0, block.length);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
java/core/src/core/crypt/CryptorRSAFactory.java
Normal file
78
java/core/src/core/crypt/CryptorRSAFactory.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
|
||||||
|
import org.bc.crypto.util.PrivateKeyFactory;
|
||||||
|
import org.bc.crypto.util.PublicKeyFactory;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.util.Base64;
|
||||||
|
import core.util.Pair;
|
||||||
|
|
||||||
|
public class CryptorRSAFactory
|
||||||
|
{
|
||||||
|
public Pair<byte[], byte[]> generate (int bits) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyPairGenerator.initialize(bits);
|
||||||
|
KeyPair keyPair = keyPairGenerator.genKeyPair();
|
||||||
|
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
||||||
|
byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||||
|
|
||||||
|
return new Pair<byte[], byte[]>(publicKey, privateKey);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate (int bits, Callback callback)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback.invoke(generate(bits));
|
||||||
|
}
|
||||||
|
catch (CryptoException e)
|
||||||
|
{
|
||||||
|
callback.invoke(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CryptorRSA fromResources(InputStream publicKey, InputStream privateKey) throws Exception
|
||||||
|
{
|
||||||
|
return new CryptorRSAJCE(publicKey, privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CryptorRSA fromString(String publicKey, String privateKey) throws Exception
|
||||||
|
{
|
||||||
|
return
|
||||||
|
new CryptorRSAJCE(
|
||||||
|
publicKey != null ?
|
||||||
|
KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(
|
||||||
|
Base64.decode(publicKey))
|
||||||
|
) :
|
||||||
|
null,
|
||||||
|
privateKey != null ?
|
||||||
|
KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(
|
||||||
|
Base64.decode(privateKey))
|
||||||
|
) :
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
83
java/core/src/core/crypt/CryptorRSAFactoryEnvironment.java
Normal file
83
java/core/src/core/crypt/CryptorRSAFactoryEnvironment.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
|
||||||
|
import org.bc.util.encoders.Base64;
|
||||||
|
|
||||||
|
import core.constants.ConstantsEnvironmentKeys;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.util.Environment;
|
||||||
|
|
||||||
|
public class CryptorRSAFactoryEnvironment
|
||||||
|
{
|
||||||
|
public static CryptorRSA createJCE (Environment env) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PublicKey publicKey = null;
|
||||||
|
PrivateKey privateKey = null;
|
||||||
|
|
||||||
|
String publicKeyString = env.get(ConstantsEnvironmentKeys.PUBLIC_ENCRYPTION_KEY);
|
||||||
|
if (publicKeyString != null)
|
||||||
|
{
|
||||||
|
publicKey =
|
||||||
|
KeyFactory.getInstance("RSA").generatePublic(
|
||||||
|
new X509EncodedKeySpec((byte[])Base64.decode(publicKeyString))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
String privateKeyString = env.get(ConstantsEnvironmentKeys.PRIVATE_DECRYPTION_KEY);
|
||||||
|
if (privateKeyString != null)
|
||||||
|
{
|
||||||
|
privateKey =
|
||||||
|
KeyFactory.getInstance("RSA").generatePrivate(
|
||||||
|
new PKCS8EncodedKeySpec((byte[])Base64.decode(privateKeyString))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CryptorRSAJCE (publicKey, privateKey);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
public static CryptorRSA createBC (Environment env) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Base64 base64 = new Base64();
|
||||||
|
|
||||||
|
String publicKeyString = env.get(ConstantsEnvironmentKeys.PUBLIC_ENCRYPTION_KEY);
|
||||||
|
byte[] publicKeyBytes = null;
|
||||||
|
if (publicKeyString != null)
|
||||||
|
publicKeyBytes = (byte[])base64.decode(publicKeyString);
|
||||||
|
|
||||||
|
String privateKeyString = env.get(ConstantsEnvironmentKeys.PRIVATE_DECRYPTION_KEY);
|
||||||
|
byte[] privateKeyBytes = null;
|
||||||
|
if (privateKeyString != null)
|
||||||
|
privateKeyBytes = base64.decode(privateKeyString);
|
||||||
|
|
||||||
|
return new CryptorRSABC (publicKeyBytes, privateKeyBytes);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
public static CryptorRSA create (Environment env) throws CryptoException
|
||||||
|
{
|
||||||
|
return createJCE(env);
|
||||||
|
}
|
||||||
|
}
|
91
java/core/src/core/crypt/CryptorRSAJCE.java
Normal file
91
java/core/src/core/crypt/CryptorRSAJCE.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class CryptorRSAJCE extends CryptorRSA
|
||||||
|
{
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
public final int MAX_RSA_BLOCK_SIZE = 117;
|
||||||
|
|
||||||
|
PublicKey publicKey;
|
||||||
|
PrivateKey privateKey;
|
||||||
|
|
||||||
|
public CryptorRSAJCE (InputStream keyStore, InputStream trustStore) throws Exception
|
||||||
|
{
|
||||||
|
if (keyStore != null)
|
||||||
|
{
|
||||||
|
KeyStore kks = KeyStore.getInstance("JKS");
|
||||||
|
kks.load(keyStore, "password".toCharArray());
|
||||||
|
privateKey = (PrivateKey)kks.getKey(kks.aliases().nextElement(), "password".toCharArray());
|
||||||
|
|
||||||
|
if (privateKey == null)
|
||||||
|
throw new CryptoException(new Exception("RSA Private Key not found in KeyStore."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trustStore != null)
|
||||||
|
{
|
||||||
|
KeyStore tks = KeyStore.getInstance("JKS");
|
||||||
|
tks.load(trustStore, "password".toCharArray());
|
||||||
|
publicKey = tks.getCertificate(tks.aliases().nextElement()).getPublicKey();
|
||||||
|
|
||||||
|
if (publicKey == null)
|
||||||
|
throw new CryptoException(new Exception("RSA Public Key not found in KeyStore."));
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
publicKey!=null ? publicKey.getEncoded() : null,
|
||||||
|
privateKey!=null ? privateKey.getEncoded() : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CryptorRSAJCE (PublicKey publicKey, PrivateKey privateKey)
|
||||||
|
{
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
publicKey!=null ? publicKey.getEncoded() : null,
|
||||||
|
privateKey!=null ? privateKey.getEncoded() : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt (byte[] block) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
return cipher.doFinal(block, 0, block.length);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt (byte[] block) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
return cipher.doFinal(block, 0, block.length);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
java/core/src/core/crypt/CryptorSeed.java
Normal file
16
java/core/src/core/crypt/CryptorSeed.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
public class CryptorSeed
|
||||||
|
{
|
||||||
|
public byte[] seed;
|
||||||
|
|
||||||
|
public CryptorSeed(byte[] seed)
|
||||||
|
{
|
||||||
|
this.seed = seed;
|
||||||
|
}
|
||||||
|
}
|
26
java/core/src/core/crypt/HashMd5.java
Normal file
26
java/core/src/core/crypt/HashMd5.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import org.bc.crypto.digests.MD5Digest;
|
||||||
|
|
||||||
|
public class HashMd5
|
||||||
|
{
|
||||||
|
public HashMd5 ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] hash (byte[] bytes)
|
||||||
|
{
|
||||||
|
MD5Digest digest = new MD5Digest();
|
||||||
|
|
||||||
|
byte[] out = new byte[digest.getDigestSize()];
|
||||||
|
digest.update(bytes, 0, bytes.length);
|
||||||
|
digest.doFinal(out, 0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
26
java/core/src/core/crypt/HashSha256.java
Normal file
26
java/core/src/core/crypt/HashSha256.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import org.bc.crypto.digests.SHA256Digest;
|
||||||
|
|
||||||
|
public class HashSha256
|
||||||
|
{
|
||||||
|
public HashSha256 ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] hash (byte[] bytes)
|
||||||
|
{
|
||||||
|
SHA256Digest digest = new SHA256Digest();
|
||||||
|
|
||||||
|
byte[] out = new byte[digest.getDigestSize()];
|
||||||
|
digest.update(bytes, 0, bytes.length);
|
||||||
|
digest.doFinal(out, 0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
32
java/core/src/core/crypt/HmacSha1.java
Normal file
32
java/core/src/core/crypt/HmacSha1.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import org.bc.crypto.digests.SHA1Digest;
|
||||||
|
import org.bc.crypto.macs.HMac;
|
||||||
|
import org.bc.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
public class HmacSha1
|
||||||
|
{
|
||||||
|
HMac mac;
|
||||||
|
byte[] key;
|
||||||
|
|
||||||
|
public HmacSha1(byte[] key)
|
||||||
|
{
|
||||||
|
mac = new HMac(new SHA1Digest());
|
||||||
|
mac.init(new KeyParameter(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] mac(byte[] bytes)
|
||||||
|
{
|
||||||
|
mac.update(bytes, 0, bytes.length);
|
||||||
|
byte[] out = new byte[mac.getMacSize()];
|
||||||
|
mac.doFinal(out, 0);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
java/core/src/core/crypt/KeyPairFromPassword.java
Normal file
75
java/core/src/core/crypt/KeyPairFromPassword.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackChain;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class KeyPairFromPassword
|
||||||
|
{
|
||||||
|
String password;
|
||||||
|
public PBE[] pbe = { new PBE(), new PBE() };
|
||||||
|
|
||||||
|
static final int CRYPTOR = 0, VERIFIER = 1;
|
||||||
|
|
||||||
|
public KeyPairFromPassword (String password)
|
||||||
|
{
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback generate_()
|
||||||
|
{
|
||||||
|
CallbackChain chain = new CallbackChain();
|
||||||
|
|
||||||
|
return chain
|
||||||
|
.addCallback(
|
||||||
|
pbe[CRYPTOR].generate_(
|
||||||
|
password,
|
||||||
|
PBE.DEFAULT_SALT[CRYPTOR],
|
||||||
|
PBE.DEFAULT_ITERATIONS,
|
||||||
|
PBE.DEFAULT_KEYLENGTH
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addCallback(
|
||||||
|
pbe[VERIFIER].generate_(
|
||||||
|
password,
|
||||||
|
PBE.DEFAULT_SALT[VERIFIER],
|
||||||
|
PBE.DEFAULT_ITERATIONS,
|
||||||
|
PBE.DEFAULT_KEYLENGTH
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addCallback(
|
||||||
|
new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(KeyPairFromPassword.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate() throws CryptoException
|
||||||
|
{
|
||||||
|
for (int i=0; i<2; ++i)
|
||||||
|
pbe[i].generate(
|
||||||
|
password,
|
||||||
|
PBE.DEFAULT_SALT[i],
|
||||||
|
PBE.DEFAULT_ITERATIONS,
|
||||||
|
PBE.DEFAULT_KEYLENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getVerifier ()
|
||||||
|
{
|
||||||
|
return pbe[VERIFIER].key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PBE getCryptor ()
|
||||||
|
{
|
||||||
|
return pbe[CRYPTOR];
|
||||||
|
}
|
||||||
|
}
|
41
java/core/src/core/crypt/KeyPairFromPasswordCryptor.java
Normal file
41
java/core/src/core/crypt/KeyPairFromPasswordCryptor.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class KeyPairFromPasswordCryptor extends Cryptor
|
||||||
|
{
|
||||||
|
KeyPairFromPassword keyPair;
|
||||||
|
|
||||||
|
public KeyPairFromPasswordCryptor (KeyPairFromPassword keyPair)
|
||||||
|
{
|
||||||
|
this.keyPair = keyPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt (byte[] clearBlock) throws CryptoException
|
||||||
|
{
|
||||||
|
return keyPair.getCryptor().encrypt(clearBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt (byte[] encryptedBlock) throws CryptoException
|
||||||
|
{
|
||||||
|
return keyPair.getCryptor().decrypt(encryptedBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callback encrypt_()
|
||||||
|
{
|
||||||
|
return keyPair.getCryptor().encrypt_();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callback decrypt_()
|
||||||
|
{
|
||||||
|
return keyPair.getCryptor().decrypt_();
|
||||||
|
}
|
||||||
|
}
|
105
java/core/src/core/crypt/PBE.java
Normal file
105
java/core/src/core/crypt/PBE.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import org.bc.crypto.PBEParametersGenerator;
|
||||||
|
import org.bc.crypto.digests.SHA256Digest;
|
||||||
|
import org.bc.crypto.generators.PKCS5S2ParametersGenerator;
|
||||||
|
import org.bc.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.crypt.Cryptor;
|
||||||
|
import core.crypt.CryptorAES;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.util.Arrays;
|
||||||
|
import core.util.Base64;
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.LogOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption
|
||||||
|
*/
|
||||||
|
public class PBE extends Cryptor
|
||||||
|
{
|
||||||
|
LogNull log = new LogNull(PBE.class);
|
||||||
|
|
||||||
|
public byte[] key = null;
|
||||||
|
Cryptor cryptorAES;
|
||||||
|
|
||||||
|
public static final int DEFAULT_ITERATIONS = 131072;
|
||||||
|
public static final int SHORT_ITERATIONS = 32768;
|
||||||
|
public static final int DEFAULT_KEYLENGTH = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bytes used to salt the key (set before making an instance)
|
||||||
|
*/
|
||||||
|
public static final byte[] DEFAULT_SALT_0 = {
|
||||||
|
(byte)0xc8, (byte)0x73, (byte)0x41, (byte)0x8c,
|
||||||
|
(byte)0x7e, (byte)0xd8, (byte)0xee, (byte)0x89
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bytes used to salt the key (set before making an instance)
|
||||||
|
*/
|
||||||
|
public static final byte[] DEFAULT_SALT_1 = {
|
||||||
|
(byte)0x12, (byte)0x53, (byte)0x14, (byte)0xbb,
|
||||||
|
(byte)0x7e, (byte)0x97, (byte)0xce, (byte)0x55
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bytes used to salt the key (set before making an instance)
|
||||||
|
*/
|
||||||
|
public static final byte[] DEFAULT_SALT_2 = {
|
||||||
|
(byte)0x0a, (byte)0x48, (byte)0x33, (byte)0xfe,
|
||||||
|
(byte)0xa7, (byte)0xc2, (byte)0x2c, (byte)0x71
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final byte[][] DEFAULT_SALT = { DEFAULT_SALT_0, DEFAULT_SALT_1, DEFAULT_SALT_2 };
|
||||||
|
|
||||||
|
public PBE ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public PBE (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException
|
||||||
|
{
|
||||||
|
generate(password,salt, iterationCount, keyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate (String password, byte[] salt, int iterationCount, int keyLength)
|
||||||
|
throws CryptoException
|
||||||
|
{
|
||||||
|
key = PBEPlatform.generate(password, salt, iterationCount, keyLength);
|
||||||
|
cryptorAES = new CryptorAES (key);
|
||||||
|
|
||||||
|
log.debug("computed", new String(Base64.encode(key)), " using ", new String(password),"salt",new String(Base64.encode(salt)), iterationCount, keyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback generate_ (String password, byte[] salt, int iterationCount, int keyLength)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
new CallbackDefault(password, salt, iterationCount, keyLength) {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
String password = V(0);
|
||||||
|
byte[] salt = V(1);
|
||||||
|
int iterationCount = (Integer)V(2);
|
||||||
|
int keyLength = (Integer)V(3);
|
||||||
|
|
||||||
|
generate(password, salt, iterationCount, keyLength);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt(byte[] clearText) throws CryptoException
|
||||||
|
{
|
||||||
|
return cryptorAES.encrypt(clearText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt(byte[] encrypted) throws CryptoException
|
||||||
|
{
|
||||||
|
return cryptorAES.decrypt(encrypted);
|
||||||
|
}
|
||||||
|
}
|
16
java/core/src/core/crypt/PBEPlatform.java
Normal file
16
java/core/src/core/crypt/PBEPlatform.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class PBEPlatform
|
||||||
|
{
|
||||||
|
static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException
|
||||||
|
{
|
||||||
|
return PBEPlatformBC.generate(password, salt, iterationCount, keyLength);
|
||||||
|
}
|
||||||
|
}
|
29
java/core/src/core/crypt/PBEPlatformBC.java
Normal file
29
java/core/src/core/crypt/PBEPlatformBC.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import org.bc.crypto.PBEParametersGenerator;
|
||||||
|
import org.bc.crypto.digests.SHA256Digest;
|
||||||
|
import org.bc.crypto.generators.PKCS5S2ParametersGenerator;
|
||||||
|
import org.bc.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class PBEPlatformBC
|
||||||
|
{
|
||||||
|
public static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength)
|
||||||
|
throws CryptoException
|
||||||
|
{
|
||||||
|
PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
|
||||||
|
generator.init(
|
||||||
|
PBEParametersGenerator.PKCS5PasswordToBytes(password.toCharArray()),
|
||||||
|
salt,
|
||||||
|
iterationCount
|
||||||
|
);
|
||||||
|
|
||||||
|
return ((KeyParameter)generator.generateDerivedParameters(keyLength)).getKey();
|
||||||
|
}
|
||||||
|
}
|
13
java/core/src/core/crypt/PBEPlatformNative.java
Normal file
13
java/core/src/core/crypt/PBEPlatformNative.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
public class PBEPlatformNative
|
||||||
|
{
|
||||||
|
public native static byte[] generate (String password, byte[] salt, int iterationCount, int keyLength);
|
||||||
|
}
|
30
java/core/src/core/crypt/PasswordValidator.java
Normal file
30
java/core/src/core/crypt/PasswordValidator.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.crypt;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
public class PasswordValidator implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public String user;
|
||||||
|
public String password;
|
||||||
|
byte[] payload;
|
||||||
|
|
||||||
|
public PasswordValidator (String user, String password, byte[] payload)
|
||||||
|
{
|
||||||
|
this.user = user;
|
||||||
|
this.password = password;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordValidator (String user, String password)
|
||||||
|
{
|
||||||
|
this(user, password, null);
|
||||||
|
}
|
||||||
|
}
|
19
java/core/src/core/exceptions/CryptoException.java
Normal file
19
java/core/src/core/exceptions/CryptoException.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.exceptions;
|
||||||
|
|
||||||
|
public class CryptoException extends Exception
|
||||||
|
{
|
||||||
|
public CryptoException (Exception e)
|
||||||
|
{
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CryptoException(String s)
|
||||||
|
{
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
23
java/core/src/core/exceptions/InternalException.java
Normal file
23
java/core/src/core/exceptions/InternalException.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.exceptions;
|
||||||
|
|
||||||
|
import org.timepedia.exporter.client.Export;
|
||||||
|
import org.timepedia.exporter.client.Exportable;
|
||||||
|
|
||||||
|
@Export
|
||||||
|
public class InternalException extends PublicMessageException implements Exportable
|
||||||
|
{
|
||||||
|
public InternalException (Exception e)
|
||||||
|
{
|
||||||
|
super("An internal error has occurred with " + e.getClass().getName(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InternalException (String with, Exception e)
|
||||||
|
{
|
||||||
|
super("An internal error has occurred with " + with, e);
|
||||||
|
}
|
||||||
|
}
|
32
java/core/src/core/exceptions/PublicMessageException.java
Normal file
32
java/core/src/core/exceptions/PublicMessageException.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.exceptions;
|
||||||
|
|
||||||
|
import org.timepedia.exporter.client.Export;
|
||||||
|
import org.timepedia.exporter.client.Exportable;
|
||||||
|
|
||||||
|
@Export
|
||||||
|
public class PublicMessageException extends RuntimeException implements Exportable
|
||||||
|
{
|
||||||
|
public String message;
|
||||||
|
|
||||||
|
public PublicMessageException (String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PublicMessageException (String message, Exception e)
|
||||||
|
{
|
||||||
|
super(e);
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage ()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
16
java/core/src/core/exceptions/UserExistsException.java
Normal file
16
java/core/src/core/exceptions/UserExistsException.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.exceptions;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class UserExistsException extends PublicMessageException
|
||||||
|
{
|
||||||
|
public UserExistsException ()
|
||||||
|
{
|
||||||
|
super("User already exists");
|
||||||
|
}
|
||||||
|
}
|
98
java/core/src/core/io/IoChain.java
Normal file
98
java/core/src/core/io/IoChain.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
public abstract class IoChain
|
||||||
|
{
|
||||||
|
protected boolean finished = false;
|
||||||
|
protected IoChain sender, receiver;
|
||||||
|
|
||||||
|
public IoChain (IoChain sender)
|
||||||
|
{
|
||||||
|
if (sender != null)
|
||||||
|
setSender(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSender (IoChain sender)
|
||||||
|
{
|
||||||
|
this.sender = sender;
|
||||||
|
sender.setReceiver (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiver (IoChain receiver)
|
||||||
|
{
|
||||||
|
this.receiver = receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send (byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
this.sender.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onReceive (byte[] object) throws Exception
|
||||||
|
{
|
||||||
|
receiver.onReceive(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void receive(byte[] object)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onReceive(object);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
onException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onException (Exception e)
|
||||||
|
{
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.onException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoChain getFinalSender ()
|
||||||
|
{
|
||||||
|
if (sender != null)
|
||||||
|
return sender.getFinalSender();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open () throws Exception
|
||||||
|
{
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void close () throws Exception
|
||||||
|
{
|
||||||
|
if (sender != null)
|
||||||
|
sender.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop () throws Exception
|
||||||
|
{
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.stop();
|
||||||
|
else
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run () throws Exception
|
||||||
|
{
|
||||||
|
if (sender != null)
|
||||||
|
sender.run();
|
||||||
|
else
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished ()
|
||||||
|
{
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
}
|
83
java/core/src/core/io/IoChainAccumulator.java
Normal file
83
java/core/src/core/io/IoChainAccumulator.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.LogOut;
|
||||||
|
|
||||||
|
public class IoChainAccumulator extends IoChain
|
||||||
|
{
|
||||||
|
LogNull log = new LogNull(IoChainAccumulator.class);
|
||||||
|
List<byte[]> out;
|
||||||
|
boolean opened, closed;
|
||||||
|
Exception exception;
|
||||||
|
|
||||||
|
public IoChainAccumulator()
|
||||||
|
{
|
||||||
|
super(null);
|
||||||
|
out = new ArrayList<byte[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
log.debug("accumulating packet");
|
||||||
|
out.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(byte[] object) throws Exception
|
||||||
|
{
|
||||||
|
super.onReceive(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open () throws Exception
|
||||||
|
{
|
||||||
|
opened = true;
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void close () throws Exception
|
||||||
|
{
|
||||||
|
closed = true;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onException(Exception e)
|
||||||
|
{
|
||||||
|
this.exception = e;
|
||||||
|
super.onException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> getAndClearPackets()
|
||||||
|
{
|
||||||
|
List<byte[]> result = out;
|
||||||
|
out = new ArrayList<byte[]>();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getAndClearException ()
|
||||||
|
{
|
||||||
|
Exception e = this.exception;
|
||||||
|
this.exception = null;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpened ()
|
||||||
|
{
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed ()
|
||||||
|
{
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
}
|
41
java/core/src/core/io/IoChainBase64.java
Normal file
41
java/core/src/core/io/IoChainBase64.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import core.util.Base64;
|
||||||
|
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.LogOut;
|
||||||
|
|
||||||
|
public class IoChainBase64 extends IoChain
|
||||||
|
{
|
||||||
|
static LogNull log = new LogNull(IoChainBase64.class);
|
||||||
|
|
||||||
|
public IoChainBase64(IoChain sender)
|
||||||
|
{
|
||||||
|
super(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
byte[] encoded = Base64.encodeBytes(packet);
|
||||||
|
// log.debug("send base64 check:", Strings.toString(Base64.decode(encoded)));
|
||||||
|
|
||||||
|
super.send(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive (byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
byte[] decoded = Base64.decodeBytes(packet);
|
||||||
|
// log.debug("onReceive:",new String(packet));
|
||||||
|
|
||||||
|
super.onReceive(decoded);
|
||||||
|
}
|
||||||
|
}
|
10
java/core/src/core/io/IoChainFinishedException.java
Normal file
10
java/core/src/core/io/IoChainFinishedException.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
public class IoChainFinishedException extends Exception {
|
||||||
|
|
||||||
|
}
|
65
java/core/src/core/io/IoChainNewLinePackets.java
Normal file
65
java/core/src/core/io/IoChainNewLinePackets.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import core.util.LogNull;
|
||||||
|
import core.util.Strings;
|
||||||
|
|
||||||
|
public class IoChainNewLinePackets extends IoChain
|
||||||
|
{
|
||||||
|
LogNull log = new LogNull(IoChainNewLinePackets.class);
|
||||||
|
List<byte[]> packets = new ArrayList<byte[]>();
|
||||||
|
ByteArrayOutputStream unfinished = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
public IoChainNewLinePackets(IoChain sender)
|
||||||
|
{
|
||||||
|
super(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
for (byte b: bytes)
|
||||||
|
{
|
||||||
|
if (b == '\n' || b == '\r')
|
||||||
|
{
|
||||||
|
log.debug("found newline");
|
||||||
|
if (unfinished.size()>0)
|
||||||
|
{
|
||||||
|
packets.add(unfinished.toByteArray());
|
||||||
|
unfinished = new ByteArrayOutputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unfinished.write(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!packets.isEmpty())
|
||||||
|
{
|
||||||
|
log.debug("recieving packet");
|
||||||
|
|
||||||
|
byte[] packet = packets.get(0);
|
||||||
|
packets.remove(0);
|
||||||
|
super.onReceive(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send (byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
bos.write(bytes);
|
||||||
|
bos.write(Strings.toBytes("\n"));
|
||||||
|
|
||||||
|
super.send(bos.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
32
java/core/src/core/io/IoChainSSLSocket.java
Normal file
32
java/core/src/core/io/IoChainSSLSocket.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
public class IoChainSSLSocket extends IoChainSocket
|
||||||
|
{
|
||||||
|
public IoChainSSLSocket(SSLContext context, String host, int port) throws Exception
|
||||||
|
{
|
||||||
|
useSocket(createSSLSocket(context, host, port));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket createSSLSocket (SSLContext context, String host, int port) throws UnknownHostException, IOException
|
||||||
|
{
|
||||||
|
SSLSocketFactory sslsocketfactory = context.getSocketFactory();
|
||||||
|
SSLSocket socket = (SSLSocket) sslsocketfactory.createSocket(host, port);
|
||||||
|
socket.setUseClientMode(true);
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
87
java/core/src/core/io/IoChainSizedPackets.java
Normal file
87
java/core/src/core/io/IoChainSizedPackets.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
|
||||||
|
import core.util.CircularByteBuffer;
|
||||||
|
|
||||||
|
public class IoChainSizedPackets extends IoChain
|
||||||
|
{
|
||||||
|
DataInputStream in;
|
||||||
|
CircularByteBuffer internalIn;
|
||||||
|
|
||||||
|
Integer nextPacket;
|
||||||
|
|
||||||
|
public IoChainSizedPackets (IoChain sender) throws IOException
|
||||||
|
{
|
||||||
|
super(sender);
|
||||||
|
|
||||||
|
internalIn = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
|
||||||
|
this.in = new DataInputStream(internalIn.getInputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ready () throws IOException
|
||||||
|
{
|
||||||
|
if (nextPacket == null)
|
||||||
|
{
|
||||||
|
if (in.available() >= Integer.SIZE/8)
|
||||||
|
nextPacket = in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextPacket != null)
|
||||||
|
return in.available() >= nextPacket;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
internalIn.getOutputStream().write(bytes);
|
||||||
|
|
||||||
|
while (ready())
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
|
int size = bytes.length;
|
||||||
|
dos.writeInt(size);
|
||||||
|
dos.write(bytes);
|
||||||
|
dos.flush();
|
||||||
|
|
||||||
|
super.send(bos.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read () throws Exception
|
||||||
|
{
|
||||||
|
if (!ready())
|
||||||
|
throw new IOException();
|
||||||
|
|
||||||
|
byte[] buf = new byte[nextPacket];
|
||||||
|
if (in.read(buf, 0, nextPacket) != nextPacket)
|
||||||
|
throw new IOException ();
|
||||||
|
|
||||||
|
nextPacket = null;
|
||||||
|
|
||||||
|
super.onReceive(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean eof () throws IOException
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
111
java/core/src/core/io/IoChainSocket.java
Normal file
111
java/core/src/core/io/IoChainSocket.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import core.util.CircularByteBuffer;
|
||||||
|
|
||||||
|
public class IoChainSocket extends IoChain implements Runnable
|
||||||
|
{
|
||||||
|
String host;
|
||||||
|
int port;
|
||||||
|
Socket socket;
|
||||||
|
|
||||||
|
InputStream in;
|
||||||
|
OutputStream out;
|
||||||
|
|
||||||
|
protected IoChainSocket() throws Exception
|
||||||
|
{
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void useSocket (Socket socket) throws Exception
|
||||||
|
{
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
in = socket.getInputStream();
|
||||||
|
out = socket.getOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoChainSocket(String host, int port)
|
||||||
|
{
|
||||||
|
super(null);
|
||||||
|
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open () throws Exception
|
||||||
|
{
|
||||||
|
if (socket == null)
|
||||||
|
useSocket(new Socket(host, port));
|
||||||
|
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void close () throws Exception
|
||||||
|
{
|
||||||
|
if (socket != null)
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean pumpBlock () throws Exception
|
||||||
|
{
|
||||||
|
CircularByteBuffer buffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
while (socket!= null && (first || in.available()>0))
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
int c = in.read();
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
throw new IoChainFinishedException();
|
||||||
|
|
||||||
|
buffer.getOutputStream().write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.getAvailable() > 0)
|
||||||
|
{
|
||||||
|
byte[] b = new byte[buffer.getAvailable()];
|
||||||
|
buffer.getInputStream().read(b);
|
||||||
|
|
||||||
|
receive(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] bytes) throws IOException
|
||||||
|
{
|
||||||
|
out.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run ()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
|
||||||
|
while (pumpBlock()) ;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
onException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
java/core/src/core/io/IoChainThread.java
Normal file
29
java/core/src/core/io/IoChainThread.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
public class IoChainThread extends Thread
|
||||||
|
{
|
||||||
|
IoChain session;
|
||||||
|
|
||||||
|
public IoChainThread (IoChain session)
|
||||||
|
{
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
((IoChain)session).run();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
java/core/src/core/io/SSLContextGenerator.java
Normal file
47
java/core/src/core/io/SSLContextGenerator.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.io;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
|
public class SSLContextGenerator
|
||||||
|
{
|
||||||
|
static public SSLContext getSslContext(InputStream clientKeyStore, InputStream serverKeyStore)
|
||||||
|
{
|
||||||
|
SSLContext sslContext = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
KeyStore cks = KeyStore.getInstance("JKS");
|
||||||
|
cks.load(clientKeyStore, "password".toCharArray());
|
||||||
|
|
||||||
|
KeyStore sks = KeyStore.getInstance("JKS");
|
||||||
|
sks.load(serverKeyStore, "password".toCharArray());
|
||||||
|
|
||||||
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||||
|
kmf.init(cks, "password".toCharArray());
|
||||||
|
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
|
||||||
|
tmf.init(sks);
|
||||||
|
|
||||||
|
// this might need to be SSL not TLS
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||||
|
|
||||||
|
return sslContext;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
return sslContext;
|
||||||
|
}
|
||||||
|
}
|
146
java/core/src/core/server/captcha/Captcha.java
Normal file
146
java/core/src/core/server/captcha/Captcha.java
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.captcha;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import core.server.captcha.sql.Catalog;
|
||||||
|
import core.util.Passwords;
|
||||||
|
|
||||||
|
|
||||||
|
public class Captcha
|
||||||
|
{
|
||||||
|
Random random = new SecureRandom();
|
||||||
|
Catalog catalog = new Catalog();
|
||||||
|
|
||||||
|
public static final String
|
||||||
|
SignUp = "SignUp",
|
||||||
|
CreateBucket = "CreateBucket";
|
||||||
|
|
||||||
|
public void prune () throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.PRUNE_TOKENS));
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void insertCaptchToken (String token, String use) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.ADD_TOKEN));
|
||||||
|
statement.setString(1, token + "_" + use);
|
||||||
|
log(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String captchaSucceeded () throws SQLException, IOException
|
||||||
|
{
|
||||||
|
String token = BigInteger.valueOf(Math.abs(random.nextLong())).toString(32);
|
||||||
|
insertCaptchToken (token, SignUp);
|
||||||
|
insertCaptchToken (token, CreateBucket);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useToken (String token, String use) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
prune();
|
||||||
|
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.CHECK_TOKEN));
|
||||||
|
statement.setString(1, token + "_" + use);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
if (!rs.next())
|
||||||
|
throw new IOException ("Null captcha");
|
||||||
|
rs.close();
|
||||||
|
|
||||||
|
statement = connection.prepareStatement (catalog.getSingle(Catalog.USE_TOKEN));
|
||||||
|
statement.setString(1, token + "_" + use);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureTables() throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (String sql : catalog.getMulti(Catalog.CREATE_TABLES))
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (sql);
|
||||||
|
log(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection openConnection () throws SQLException, IOException
|
||||||
|
{
|
||||||
|
return DriverManager.getConnection(Catalog.CONNECTION_STRING, Catalog.USER, Passwords.getPasswordFor(Catalog.USER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeConnection (Connection connection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (connection != null)
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log (Statement sql)
|
||||||
|
{
|
||||||
|
System.out.println (sql);
|
||||||
|
}
|
||||||
|
}
|
22
java/core/src/core/server/captcha/sql/Catalog.java
Normal file
22
java/core/src/core/server/captcha/sql/Catalog.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.captcha.sql;
|
||||||
|
|
||||||
|
import core.constants.ConstantsServer;
|
||||||
|
import core.util.SqlCatalog;
|
||||||
|
|
||||||
|
|
||||||
|
public final class Catalog extends SqlCatalog
|
||||||
|
{
|
||||||
|
static public final String CONNECTION_STRING = ConstantsServer.DBCONNECTION_PREFIX + "captcha";
|
||||||
|
public static final String USER = "captcha";
|
||||||
|
|
||||||
|
static public final String CREATE_TABLES = "create_tables";
|
||||||
|
static public final String USE_TOKEN = "use_token";
|
||||||
|
static public final String CHECK_TOKEN = "check_token";
|
||||||
|
static public final String ADD_TOKEN = "add_token";
|
||||||
|
static public final String PRUNE_TOKENS = "prune_tokens";
|
||||||
|
}
|
1
java/core/src/core/server/captcha/sql/add_token
Normal file
1
java/core/src/core/server/captcha/sql/add_token
Normal file
@ -0,0 +1 @@
|
|||||||
|
INSERT INTO captcha (token) values (?)
|
1
java/core/src/core/server/captcha/sql/check_token
Normal file
1
java/core/src/core/server/captcha/sql/check_token
Normal file
@ -0,0 +1 @@
|
|||||||
|
SELECT true FROM captcha WHERE token=?
|
5
java/core/src/core/server/captcha/sql/create_tables
Normal file
5
java/core/src/core/server/captcha/sql/create_tables
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS captcha (
|
||||||
|
token VARCHAR(255),
|
||||||
|
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (token)
|
||||||
|
)
|
1
java/core/src/core/server/captcha/sql/prune_tokens
Normal file
1
java/core/src/core/server/captcha/sql/prune_tokens
Normal file
@ -0,0 +1 @@
|
|||||||
|
DELETE FROM captcha WHERE mark < DATE_SUB(now(), INTERVAL 2 HOUR);
|
1
java/core/src/core/server/captcha/sql/use_token
Normal file
1
java/core/src/core/server/captcha/sql/use_token
Normal file
@ -0,0 +1 @@
|
|||||||
|
DELETE FROM captcha WHERE token=?
|
479
java/core/src/core/server/db/UserDb.java
Normal file
479
java/core/src/core/server/db/UserDb.java
Normal file
@ -0,0 +1,479 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.srp.db;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.exceptions.PublicMessageException;
|
||||||
|
import core.exceptions.UserExistsException;
|
||||||
|
import core.server.srp.db.sql.Catalog;
|
||||||
|
import core.util.LogOut;
|
||||||
|
import core.util.Pair;
|
||||||
|
import core.util.Passwords;
|
||||||
|
import core.util.Strings;
|
||||||
|
import core.util.Triple;
|
||||||
|
import core.util.Base64;
|
||||||
|
|
||||||
|
public abstract class UserDb
|
||||||
|
{
|
||||||
|
static LogOut log = new LogOut(UserDb.class);
|
||||||
|
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
Catalog catalog;
|
||||||
|
|
||||||
|
protected UserDb (Catalog catalog)
|
||||||
|
{
|
||||||
|
this.catalog = catalog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateUser (String version, String userName) throws Exception
|
||||||
|
{
|
||||||
|
checkRoomForNewUser();
|
||||||
|
testIllegalUserName(userName);
|
||||||
|
|
||||||
|
if (getUser(userName)!=null)
|
||||||
|
throw new UserExistsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkRoomForNewUser () throws Exception
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.ROOM_FOR_NEW_USER));
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
{
|
||||||
|
boolean hasRoom = results.getBoolean("room");
|
||||||
|
if (hasRoom)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PublicMessageException("No room for new users");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUserId (String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
return getUser(userName).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createUser(String version, String userName, byte[] v, byte[] s) throws Exception
|
||||||
|
{
|
||||||
|
checkRoomForNewUser();
|
||||||
|
testIllegalUserName(userName);
|
||||||
|
|
||||||
|
if (getUser(userName)!=null)
|
||||||
|
throw new UserExistsException();
|
||||||
|
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.CREATE_USER));
|
||||||
|
statement.setString(1, version);
|
||||||
|
statement.setString(2, userName);
|
||||||
|
statement.setString(3, Base64.encode(v));
|
||||||
|
statement.setString(4, Base64.encode(s));
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Pair<Integer, Triple<String, byte[], byte[]> > getUser (String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
Pair<Integer, Triple<String, byte[], byte[]>> result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
new Pair<Integer, Triple<String, byte[], byte[] > >(
|
||||||
|
results.getInt("id"),
|
||||||
|
new Triple<String, byte[], byte[]> (
|
||||||
|
results.getString("version"),
|
||||||
|
Base64.decode(results.getString("v")),
|
||||||
|
Base64.decode(results.getString("s"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triple<String, BigInteger, BigInteger> getVVS (String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Triple<String, byte[], byte[]> vvs = getUser(userName).second;
|
||||||
|
return
|
||||||
|
new Triple<String, BigInteger, BigInteger>(
|
||||||
|
vvs.first,
|
||||||
|
new BigInteger (vvs.second),
|
||||||
|
new BigInteger (vvs.third)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] setMailBlock (String userName, byte[] block) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Integer id = getUser(userName).first;
|
||||||
|
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.SET_USER_MAIL_BLOCK));
|
||||||
|
statement.setInt(1, id);
|
||||||
|
statement.setString (2, Base64.encode(block));
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public byte[] setBlock (String userName, byte[] block) throws IOException, SQLException, CryptoException;
|
||||||
|
abstract public byte[] getBlock (String userName) throws IOException, SQLException, CryptoException;
|
||||||
|
|
||||||
|
protected byte[] setKeyBlock (String userName, byte[] block) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Integer id = getUser(userName).first;
|
||||||
|
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.SET_USER_KEY_BLOCK));
|
||||||
|
statement.setInt(1, id);
|
||||||
|
statement.setString (2, Base64.encode(block));
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] getMailBlock (String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER_MAIL_BLOCK));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
result = Base64.decode(results.getString("block"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getDeletedMailBlock(String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_DELETED_USER_MAIL_BLOCK));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
result = Base64.decode(results.getString("block"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeletedUser() throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_DELETED_USER));
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
result = results.getString("name");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] getKeyBlock (String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
byte[] result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_USER_KEY_BLOCK));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet results = statement.executeQuery();
|
||||||
|
if (results.next())
|
||||||
|
result = Base64.decode(results.getString("block"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureTables() throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (String sql : catalog.getMulti(catalog.CREATE_TABLES))
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (sql);
|
||||||
|
log(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rateLimitFailure (String userName) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.GET_LAST_FAILURE));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
log(statement);
|
||||||
|
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
if (rs.next())
|
||||||
|
{
|
||||||
|
Timestamp timeStamp = rs.getTimestamp("mark");
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
if (now.getTime() - timeStamp.getTime() < catalog.FAILURE_TIMEOUT_SECONDS * 1000)
|
||||||
|
throw new PublicMessageException ("Too many failures, try again later.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markFailure (String userName) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(catalog.MARK_FAILURE));
|
||||||
|
statement.setString(1, userName);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteUser(String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String[] texts = catalog.getMulti(catalog.DELETE);
|
||||||
|
for (String text : texts)
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (text);
|
||||||
|
statement.setString(1, userName);
|
||||||
|
|
||||||
|
log(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expungeUser(String userName) throws IOException, SQLException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String[] texts = catalog.getMulti(catalog.EXPUNGE);
|
||||||
|
for (String text : texts)
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (text);
|
||||||
|
statement.setString(1, userName);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection openConnection () throws IOException, SQLException
|
||||||
|
{
|
||||||
|
log.debug("Connecting to", catalog.CONNECTION_STRING);
|
||||||
|
return DriverManager.getConnection(catalog.CONNECTION_STRING, catalog.USER, Passwords.getPasswordFor(catalog.USER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeConnection (Connection connection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (connection != null)
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public void log (Statement sql)
|
||||||
|
{
|
||||||
|
System.out.println (sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void testIllegalUserName(String userName) throws Exception
|
||||||
|
{
|
||||||
|
// http://www.ietf.org/rfc/rfc2142.txt
|
||||||
|
final String[] illegalStartsWith = {
|
||||||
|
"info",
|
||||||
|
"marketing",
|
||||||
|
"sales",
|
||||||
|
"support",
|
||||||
|
|
||||||
|
"abuse",
|
||||||
|
"noc",
|
||||||
|
"security",
|
||||||
|
|
||||||
|
"postmaster",
|
||||||
|
"hostmaster",
|
||||||
|
"usenet",
|
||||||
|
"news",
|
||||||
|
"webmaster",
|
||||||
|
"www",
|
||||||
|
"uucp",
|
||||||
|
"ftp",
|
||||||
|
|
||||||
|
"admin",
|
||||||
|
"system",
|
||||||
|
"root",
|
||||||
|
"test",
|
||||||
|
"root",
|
||||||
|
"hostma",
|
||||||
|
"web",
|
||||||
|
"post",
|
||||||
|
"mail",
|
||||||
|
};
|
||||||
|
|
||||||
|
final String[] illegalParts = {
|
||||||
|
"postmaster",
|
||||||
|
"webmaster",
|
||||||
|
"root",
|
||||||
|
"admin",
|
||||||
|
"system",
|
||||||
|
};
|
||||||
|
|
||||||
|
String username = userName.toLowerCase();
|
||||||
|
for (String illegal : illegalParts)
|
||||||
|
{
|
||||||
|
if (username.indexOf(illegal) != -1)
|
||||||
|
throw new Exception("Illegal username");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String illegal : illegalStartsWith)
|
||||||
|
{
|
||||||
|
if (username.startsWith(illegal))
|
||||||
|
throw new Exception("Illegal username");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
java/core/src/core/server/db/sql/Catalog.java
Normal file
51
java/core/src/core/server/db/sql/Catalog.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.srp.db.sql;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import core.constants.ConstantsServer;
|
||||||
|
import core.util.Passwords;
|
||||||
|
import core.util.SqlCatalog;
|
||||||
|
import core.util.Streams;
|
||||||
|
|
||||||
|
|
||||||
|
public final class Catalog extends SqlCatalog
|
||||||
|
{
|
||||||
|
public String CONNECTION_STRING = ConstantsServer.DBCONNECTION_PREFIX + "mail";
|
||||||
|
public String USER = "mail";
|
||||||
|
|
||||||
|
public int FAILURE_TIMEOUT_SECONDS = 60;
|
||||||
|
|
||||||
|
public final String
|
||||||
|
CREATE_TABLES = "create_tables",
|
||||||
|
CREATE_USER = "create_user",
|
||||||
|
GET_USER = "get_user",
|
||||||
|
GET_USER_MAIL_BLOCK = "get_user_mail_block",
|
||||||
|
SET_USER_MAIL_BLOCK = "set_user_mail_block",
|
||||||
|
GET_USER_KEY_BLOCK = "get_user_key_block",
|
||||||
|
SET_USER_KEY_BLOCK = "set_user_key_block",
|
||||||
|
GET_LAST_FAILURE = "get_last_failure",
|
||||||
|
MARK_FAILURE = "mark_failure",
|
||||||
|
|
||||||
|
DELETE = "delete_user.sql",
|
||||||
|
EXPUNGE = "expunge_deleted_user.sql",
|
||||||
|
GET_DELETED_USER = "get_deleted_user.sql",
|
||||||
|
GET_DELETED_USER_MAIL_BLOCK = "get_deleted_user_mail_block.sql",
|
||||||
|
|
||||||
|
ROOM_FOR_NEW_USER = "room_for_new_user";
|
||||||
|
|
||||||
|
public Catalog ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword () throws IOException
|
||||||
|
{
|
||||||
|
return Passwords.getPasswordFor(USER);
|
||||||
|
}
|
||||||
|
}
|
55
java/core/src/core/server/db/sql/create_tables
Normal file
55
java/core/src/core/server/db/sql/create_tables
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS registry (
|
||||||
|
k VARCHAR(50),
|
||||||
|
v VARCHAR(255),
|
||||||
|
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (k)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO registry (k,v) VALUES ("max_users", "1000");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
|
version VARCHAR(50),
|
||||||
|
id INTEGER AUTO_INCREMENT,
|
||||||
|
name VARCHAR(255) COLLATE utf8_general_ci NOT NULL DEFAULT '',
|
||||||
|
v TEXT,
|
||||||
|
s TEXT,
|
||||||
|
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (name),
|
||||||
|
UNIQUE KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS mail_block (
|
||||||
|
user_id INTEGER,
|
||||||
|
block TEXT,
|
||||||
|
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS key_block (
|
||||||
|
user_id INTEGER,
|
||||||
|
block TEXT,
|
||||||
|
mark TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS failure (
|
||||||
|
user_id INTEGER,
|
||||||
|
mark TIMESTAMP,
|
||||||
|
PRIMARY KEY (user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS deleted_user (
|
||||||
|
version VARCHAR(50),
|
||||||
|
id INTEGER AUTO_INCREMENT,
|
||||||
|
name VARCHAR(255) COLLATE utf8_general_ci NOT NULL DEFAULT '',
|
||||||
|
v TEXT,
|
||||||
|
s TEXT,
|
||||||
|
mark TIMESTAMP NULL DEFAULT NULL,
|
||||||
|
deleted TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS deleted_mail_block LIKE mail_block;
|
||||||
|
CREATE TABLE IF NOT EXISTS deleted_key_block LIKE key_block;
|
||||||
|
DROP TABLE IF EXISTS metadata;
|
||||||
|
|
1
java/core/src/core/server/db/sql/create_user
Normal file
1
java/core/src/core/server/db/sql/create_user
Normal file
@ -0,0 +1 @@
|
|||||||
|
INSERT INTO user (version, name, v, s) VALUES (?, ?, ?, ?)
|
24
java/core/src/core/server/db/sql/delete_user.sql
Normal file
24
java/core/src/core/server/db/sql/delete_user.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
REPLACE INTO deleted_mail_block
|
||||||
|
SELECT mail_block.*
|
||||||
|
FROM mail_block, user
|
||||||
|
WHERE user.name=? AND mail_block.user_id = user.id;
|
||||||
|
|
||||||
|
REPLACE INTO deleted_key_block
|
||||||
|
SELECT key_block.*
|
||||||
|
FROM key_block, user
|
||||||
|
WHERE user.name=? AND key_block.user_id = user.id;
|
||||||
|
|
||||||
|
REPLACE INTO deleted_user(version, id, name, v, s, mark)
|
||||||
|
SELECT version, id, name, v, s, mark
|
||||||
|
FROM user
|
||||||
|
WHERE user.name=?;
|
||||||
|
|
||||||
|
DELETE mail_block.*
|
||||||
|
FROM mail_block, user
|
||||||
|
WHERE user.name=? AND mail_block.user_id = user.id;
|
||||||
|
|
||||||
|
DELETE key_block.*
|
||||||
|
FROM key_block, user
|
||||||
|
WHERE user.name=? AND key_block.user_id = user.id;
|
||||||
|
|
||||||
|
DELETE FROM user WHERE user.name=?
|
@ -0,0 +1,9 @@
|
|||||||
|
DELETE deleted_mail_block.*
|
||||||
|
FROM deleted_mail_block, deleted_user
|
||||||
|
WHERE deleted_user.name=? AND deleted_mail_block.user_id = deleted_user.id;
|
||||||
|
|
||||||
|
DELETE deleted_key_block.*
|
||||||
|
FROM deleted_key_block, deleted_user
|
||||||
|
WHERE deleted_user.name=? AND deleted_key_block.user_id = deleted_user.id;
|
||||||
|
|
||||||
|
DELETE FROM deleted_user WHERE deleted_user.name=?
|
7
java/core/src/core/server/db/sql/get_deleted_user.sql
Normal file
7
java/core/src/core/server/db/sql/get_deleted_user.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
select
|
||||||
|
*
|
||||||
|
from
|
||||||
|
deleted_user
|
||||||
|
order by
|
||||||
|
deleted
|
||||||
|
limit 1
|
@ -0,0 +1,8 @@
|
|||||||
|
SELECT
|
||||||
|
deleted_mail_block.*
|
||||||
|
FROM
|
||||||
|
deleted_user,
|
||||||
|
deleted_mail_block
|
||||||
|
WHERE
|
||||||
|
deleted_mail_block.user_id = deleted_user.id AND
|
||||||
|
deleted_user.name = ?
|
8
java/core/src/core/server/db/sql/get_last_failure
Normal file
8
java/core/src/core/server/db/sql/get_last_failure
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT
|
||||||
|
failure.mark
|
||||||
|
FROM
|
||||||
|
user,
|
||||||
|
failure
|
||||||
|
WHERE
|
||||||
|
user.name = ? AND
|
||||||
|
failure.user_id = user.id
|
6
java/core/src/core/server/db/sql/get_user
Normal file
6
java/core/src/core/server/db/sql/get_user
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
WHERE
|
||||||
|
user.name = ?
|
8
java/core/src/core/server/db/sql/get_user_key_block
Normal file
8
java/core/src/core/server/db/sql/get_user_key_block
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT
|
||||||
|
key_block.*
|
||||||
|
FROM
|
||||||
|
user,
|
||||||
|
key_block
|
||||||
|
WHERE
|
||||||
|
key_block.user_id = user.id AND
|
||||||
|
user.name = ?
|
8
java/core/src/core/server/db/sql/get_user_mail_block
Normal file
8
java/core/src/core/server/db/sql/get_user_mail_block
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT
|
||||||
|
mail_block.*
|
||||||
|
FROM
|
||||||
|
user,
|
||||||
|
mail_block
|
||||||
|
WHERE
|
||||||
|
mail_block.user_id = user.id AND
|
||||||
|
user.name = ?
|
8
java/core/src/core/server/db/sql/mark_failure
Normal file
8
java/core/src/core/server/db/sql/mark_failure
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
REPLACE INTO failure (user_id, mark)
|
||||||
|
SELECT
|
||||||
|
id as user_id,
|
||||||
|
now() as mark
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
WHERE
|
||||||
|
name = ?
|
4
java/core/src/core/server/db/sql/room_for_new_user
Normal file
4
java/core/src/core/server/db/sql/room_for_new_user
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
select
|
||||||
|
count(*) < (select convert(v, unsigned integer) from registry where k="max_users") as room
|
||||||
|
from
|
||||||
|
user
|
1
java/core/src/core/server/db/sql/set_user_key_block
Normal file
1
java/core/src/core/server/db/sql/set_user_key_block
Normal file
@ -0,0 +1 @@
|
|||||||
|
REPLACE INTO key_block (user_id, block) VALUES (?, ?)
|
1
java/core/src/core/server/db/sql/set_user_mail_block
Normal file
1
java/core/src/core/server/db/sql/set_user_mail_block
Normal file
@ -0,0 +1 @@
|
|||||||
|
REPLACE INTO mail_block (user_id, block) VALUES (?, ?)
|
51
java/core/src/core/server/log/Tail.java
Normal file
51
java/core/src/core/server/log/Tail.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Tail
|
||||||
|
{
|
||||||
|
static final int TAIL_INTERVAL = 1000;
|
||||||
|
|
||||||
|
String fileName;
|
||||||
|
String lastTail;
|
||||||
|
Date lastTailTime;
|
||||||
|
|
||||||
|
public Tail (String fileName)
|
||||||
|
{
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTail () throws IOException
|
||||||
|
{
|
||||||
|
Date now = new Date();
|
||||||
|
if (lastTailTime != null &&
|
||||||
|
now.getTime() < lastTailTime.getTime() + TAIL_INTERVAL)
|
||||||
|
return lastTail;
|
||||||
|
|
||||||
|
lastTailTime = now;
|
||||||
|
lastTail = null;
|
||||||
|
|
||||||
|
File file = new File(fileName);
|
||||||
|
RandomAccessFile fileHandler = new RandomAccessFile( file, "r" );
|
||||||
|
long fileLength = file.length() - 1;
|
||||||
|
long blockLength = Math.min(fileLength, 4096);
|
||||||
|
|
||||||
|
fileHandler.seek(fileLength - blockLength);
|
||||||
|
|
||||||
|
byte[] bytes = new byte[(int) blockLength];
|
||||||
|
fileHandler.readFully(bytes);
|
||||||
|
fileHandler.close();
|
||||||
|
|
||||||
|
lastTail = new String(bytes, "UTF-8");
|
||||||
|
return lastTail;
|
||||||
|
}
|
||||||
|
}
|
220
java/core/src/core/server/mailextra/MailExtraDb.java
Normal file
220
java/core/src/core/server/mailextra/MailExtraDb.java
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.mailextra;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.bc.util.Strings;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import core.util.Base64;
|
||||||
|
import core.constants.ConstantsPushNotifications;
|
||||||
|
import core.crypt.HashSha256;
|
||||||
|
import core.server.mailextra.sql.Catalog;
|
||||||
|
import core.util.LogOut;
|
||||||
|
import core.util.Pair;
|
||||||
|
import core.util.Passwords;
|
||||||
|
import core.util.Triple;
|
||||||
|
|
||||||
|
public class MailExtraDb
|
||||||
|
{
|
||||||
|
LogOut log = new LogOut(MailExtraDb.class);
|
||||||
|
Catalog catalog = new Catalog();
|
||||||
|
|
||||||
|
public String getUserHash (String email)
|
||||||
|
{
|
||||||
|
HashSha256 hasher = new HashSha256();
|
||||||
|
return Base64.encode(hasher.hash(Strings.toByteArray(email.toLowerCase())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triple<String,String,String> getDeviceFor (String email) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
return getDeviceForHash(getUserHash(email));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triple<String,String,String> getDeviceForHash (String hash) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
|
||||||
|
Connection connection = openConnection();
|
||||||
|
Triple<String,String,String> result;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.GET_NOTIFICATIONS_FOR));
|
||||||
|
statement.setString(1, hash);
|
||||||
|
log.debug(statement);
|
||||||
|
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
if (!rs.next())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
result = new Triple<String,String,String>(rs.getString("notification_type"), rs.getString("device_type"), rs.getString("device_id"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsFor (String email, String notificationType, String deviceType, String deviceId) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
setNotificationsFor (getUserHash(email), deviceType, deviceId, notificationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsForHash (String hash, String notificationType, String deviceType, String deviceId) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String statements[] = catalog.getMulti(Catalog.SET_NOTIFICATIONS_FOR);
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
for (String s : statements)
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (s);
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
statement.setString(1, hash);
|
||||||
|
statement.setString(2, notificationType);
|
||||||
|
statement.setString(3, deviceType);
|
||||||
|
statement.setString(4, deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDaysTo (String email, int days) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String statements[] = catalog.getMulti(Catalog.ADD_DAYS_TO);
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
for (String s : statements)
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (s);
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
statement.setString(1, email);
|
||||||
|
statement.setInt(2, days);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log.debug(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDaysLeft (String email) throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log.debug(catalog.getSingle(Catalog.GET_DAYS_LEFT));
|
||||||
|
PreparedStatement statement = connection.prepareStatement (catalog.getSingle(Catalog.GET_DAYS_LEFT));
|
||||||
|
statement.setString(1, email);
|
||||||
|
log.debug(statement);
|
||||||
|
|
||||||
|
ResultSet rs = statement.executeQuery();
|
||||||
|
if (!rs.next())
|
||||||
|
throw new IOException ("No results");
|
||||||
|
|
||||||
|
int days = rs.getInt("days");
|
||||||
|
rs.close();
|
||||||
|
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureTables() throws SQLException, IOException
|
||||||
|
{
|
||||||
|
Connection connection = openConnection();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (String sql : catalog.getMulti(Catalog.CREATE_TABLES))
|
||||||
|
{
|
||||||
|
PreparedStatement statement = connection.prepareStatement (sql);
|
||||||
|
log.debug(statement);
|
||||||
|
statement.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
closeConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection openConnection () throws SQLException, IOException
|
||||||
|
{
|
||||||
|
return DriverManager.getConnection(Catalog.CONNECTION_STRING, Catalog.USER, Passwords.getPasswordFor(Catalog.USER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeConnection (Connection connection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (connection != null)
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePushNotificationsJson(JSONObject json) throws JSONException, SQLException, IOException
|
||||||
|
{
|
||||||
|
String user = json.getString(ConstantsPushNotifications.USER);
|
||||||
|
|
||||||
|
setNotificationsForHash(
|
||||||
|
user,
|
||||||
|
json.getString(ConstantsPushNotifications.NOTIFICATION_TYPE),
|
||||||
|
json.has(ConstantsPushNotifications.DEVICE_TYPE) ?
|
||||||
|
json.getString(ConstantsPushNotifications.DEVICE_TYPE) : null,
|
||||||
|
json.has(ConstantsPushNotifications.DEVICE_ID) ?
|
||||||
|
json.getString(ConstantsPushNotifications.DEVICE_ID) : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeDevice(String deviceType, String deviceId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
java/core/src/core/server/mailextra/sql/Catalog.java
Normal file
25
java/core/src/core/server/mailextra/sql/Catalog.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.server.mailextra.sql;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import core.util.SqlCatalog;
|
||||||
|
import core.util.Streams;
|
||||||
|
|
||||||
|
public class Catalog extends SqlCatalog
|
||||||
|
{
|
||||||
|
static public final String CONNECTION_STRING = "jdbc:mysql://localhost/mail_extra";
|
||||||
|
public static final String USER = "mail_extra";
|
||||||
|
|
||||||
|
static public final String GET_NOTIFICATIONS_FOR = "get_notifications_for.sql";
|
||||||
|
static public final String SET_NOTIFICATIONS_FOR = "set_notifications_for.sql";
|
||||||
|
static public final String PRUNE_DEVICES = "prune_devices.sql";
|
||||||
|
|
||||||
|
static public final String CREATE_TABLES = "create_tables";
|
||||||
|
static public final String ADD_DAYS_TO = "add_days_to";
|
||||||
|
static public final String GET_DAYS_LEFT = "get_days_left";
|
||||||
|
}
|
10
java/core/src/core/server/mailextra/sql/add_days_to
Normal file
10
java/core/src/core/server/mailextra/sql/add_days_to
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
SET @email = ?, @days = ?;
|
||||||
|
|
||||||
|
INSERT INTO expirations (email, expiration) VALUES(@email, DATE_ADD(CURDATE(), INTERVAL @days DAY))
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
expiration =
|
||||||
|
IF(
|
||||||
|
DATEDIFF(expiration, CURDATE())>0,
|
||||||
|
DATE_ADD(expiration, INTERVAL @days DAY),
|
||||||
|
VALUES(expiration)
|
||||||
|
)
|
15
java/core/src/core/server/mailextra/sql/create_tables
Normal file
15
java/core/src/core/server/mailextra/sql/create_tables
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS expirations (
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
expiration DATE NOT NULL,
|
||||||
|
PRIMARY KEY (email)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `device` (
|
||||||
|
`email` VARCHAR(255) NOT NULL,
|
||||||
|
`notification_type` ENUM('NONE','SHORT','LONG') NOT NULL,
|
||||||
|
`device_type` VARCHAR(255) DEFAULT NULL,
|
||||||
|
`device_id` VARCHAR(255) DEFAULT NULL,
|
||||||
|
`mark` date NOT NULL,
|
||||||
|
PRIMARY KEY (`email`),
|
||||||
|
KEY `device` (`device_type`,`device_id`)
|
||||||
|
);
|
6
java/core/src/core/server/mailextra/sql/get_days_left
Normal file
6
java/core/src/core/server/mailextra/sql/get_days_left
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT
|
||||||
|
DATEDIFF(expiration, CURDATE()) as days
|
||||||
|
FROM
|
||||||
|
expirations
|
||||||
|
WHERE
|
||||||
|
expirations.email = ?
|
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
device.notification_type,
|
||||||
|
device.device_type,
|
||||||
|
device.device_id,
|
||||||
|
device.mark
|
||||||
|
FROM
|
||||||
|
device
|
||||||
|
WHERE
|
||||||
|
device.email = ?
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
SET @email = ?, @notification_type = ?, @device_type = ?, @device_id = ?;
|
||||||
|
|
||||||
|
DELETE FROM device WHERE device_type = @device_type AND device_id = @device_id;
|
||||||
|
REPLACE INTO device (email, device_type, device_id, notification_type, mark) VALUES(@email, @device_type, @device_id, @notification_type, now())
|
301
java/core/src/core/srp/SRPPacketSerializerJSON.java
Normal file
301
java/core/src/core/srp/SRPPacketSerializerJSON.java
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import core.util.Base64;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import core.util.CallSingle;
|
||||||
|
import core.util.JSONRegistry;
|
||||||
|
import core.util.Strings;
|
||||||
|
|
||||||
|
|
||||||
|
public class SRPPacketSerializerJSON
|
||||||
|
{
|
||||||
|
static public void register () {}
|
||||||
|
|
||||||
|
static {
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet1_ClientSendsHello",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet1_ClientSendsHello p = (SRPPackets.Packet1_ClientSendsHello)v;
|
||||||
|
object.put("user", p.user);
|
||||||
|
object.put("version", p.version);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet1_ClientSendsHello(
|
||||||
|
v.get("user").toString(),
|
||||||
|
v.get("version").toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet2_ServerSendSalt",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet2_ServerSendSalt p = (SRPPackets.Packet2_ServerSendSalt)v;
|
||||||
|
object.put("salt", Base64.encode(p.salt));
|
||||||
|
object.put("version", p.version);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet2_ServerSendSalt(
|
||||||
|
v.get("version").toString(),
|
||||||
|
Base64.decode(v.get("salt").toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet3_ClientSendPublicKey",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet3_ClientSendPublicKey p = (SRPPackets.Packet3_ClientSendPublicKey)v;
|
||||||
|
object.put("publicKey", new String(Base64.encode(p.publicKey)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet3_ClientSendPublicKey(
|
||||||
|
Base64.decode(v.get("publicKey").toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet4_ServerSendPublicKey",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet4_ServerSendPublicKey p = (SRPPackets.Packet4_ServerSendPublicKey)v;
|
||||||
|
object.put("publicKey", new String(Base64.encode(p.publicKey)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet4_ServerSendPublicKey(
|
||||||
|
new BigInteger(Base64.decode(v.get("publicKey").toString()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet5_ClientSendEvidence",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet5_ClientSendEvidence p = (SRPPackets.Packet5_ClientSendEvidence)v;
|
||||||
|
object.put("evidence", new String(Base64.encode(p.evidence)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet5_ClientSendEvidence(
|
||||||
|
Base64.decode(v.get("evidence").toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$Packet6_ServerSendEvidenceAndPayload",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.Packet6_ServerSendEvidenceAndPayload p = (SRPPackets.Packet6_ServerSendEvidenceAndPayload)v;
|
||||||
|
object.put("evidence", new String(Base64.encode(p.evidence)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet6_ServerSendEvidenceAndPayload(
|
||||||
|
new BigInteger(Base64.decode(v.get("evidence").toString()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$PacketInit_ClientTestCreate",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.PacketInit_ClientTestCreate p = (SRPPackets.PacketInit_ClientTestCreate)v;
|
||||||
|
object.put("user", p.user);
|
||||||
|
object.put("version", p.version);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
SRPPackets.PacketInit_ClientTestCreate(
|
||||||
|
v.getString("version"),
|
||||||
|
v.getString("user")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$PacketInit_EncryptedPacket",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.PacketInit_EncryptedPacket p = (SRPPackets.PacketInit_EncryptedPacket)v;
|
||||||
|
object.put("encryptedBlock", new String(Base64.encode(p.encryptedBlock)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
SRPPackets.PacketInit_EncryptedPacket(
|
||||||
|
Base64.decode(v.getString("encryptedBlock"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$PacketInit_ServerResponse",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.PacketInit_ServerResponse p = (SRPPackets.PacketInit_ServerResponse)v;
|
||||||
|
object.put("succeeded", p.succeeded);
|
||||||
|
object.put("reason", p.reason);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
SRPPackets.PacketInit_ServerResponse(
|
||||||
|
v.getBoolean("succeeded"),
|
||||||
|
v.has("reason") ? v.getString("reason") : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
JSONRegistry.register (
|
||||||
|
"core.srp.SRPPackets$PacketInit_ClientPreAutheticationInitialization",
|
||||||
|
new CallSingle<JSONObject,Object> () {
|
||||||
|
@Override
|
||||||
|
public JSONObject invoke(Object v) throws Exception
|
||||||
|
{
|
||||||
|
JSONObject object = new JSONObject();
|
||||||
|
|
||||||
|
SRPPackets.PacketInit_ClientPreAutheticationInitialization p = (SRPPackets.PacketInit_ClientPreAutheticationInitialization)v;
|
||||||
|
object.put("version", p.version);
|
||||||
|
object.put("user", p.user);
|
||||||
|
object.put("s", new String(Base64.encode(p.s)));
|
||||||
|
object.put("v", new String(Base64.encode(p.v)));
|
||||||
|
|
||||||
|
if (p.extra != null)
|
||||||
|
object.put("extra", new String(Base64.encode(p.extra)));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new CallSingle<Object,JSONObject> () {
|
||||||
|
@Override
|
||||||
|
public Object invoke(JSONObject v) throws Exception
|
||||||
|
{
|
||||||
|
SRPPackets.PacketInit_ClientPreAutheticationInitialization p =
|
||||||
|
new SRPPackets.PacketInit_ClientPreAutheticationInitialization(
|
||||||
|
v.getString("version"),
|
||||||
|
v.getString("user"),
|
||||||
|
Base64.decode(v.getString("v")),
|
||||||
|
Base64.decode(v.getString("s"))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (v.has("extra"))
|
||||||
|
p.extra = Base64.decode(v.getString("extra"));
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
182
java/core/src/core/srp/SRPPackets.java
Normal file
182
java/core/src/core/srp/SRPPackets.java
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
|
||||||
|
|
||||||
|
public class SRPPackets
|
||||||
|
{
|
||||||
|
public static void register () { }
|
||||||
|
static {
|
||||||
|
SRPPacketSerializerJSON.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PacketInit_ClientTestCreate
|
||||||
|
{
|
||||||
|
public String version;
|
||||||
|
public String user;
|
||||||
|
|
||||||
|
public PacketInit_ClientTestCreate(String version, String user)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PacketInit_ClientPreAutheticationInitialization
|
||||||
|
{
|
||||||
|
public String user;
|
||||||
|
public byte[] v;
|
||||||
|
public byte[] s;
|
||||||
|
public byte[] extra;
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
public PacketInit_ClientPreAutheticationInitialization(String version, String user, byte[] v, byte[] s)
|
||||||
|
{
|
||||||
|
this.version = version;
|
||||||
|
this.user = user;
|
||||||
|
this.v = v;
|
||||||
|
this.s = s;
|
||||||
|
extra = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PacketInit_EncryptedPacket
|
||||||
|
{
|
||||||
|
public byte[] encryptedBlock;
|
||||||
|
|
||||||
|
public PacketInit_EncryptedPacket (byte[] encryptedBlock)
|
||||||
|
{
|
||||||
|
this.encryptedBlock = encryptedBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback wrap_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
callback.invoke(new PacketInit_EncryptedPacket((byte[])(arguments[0])));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback unwrap_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
PacketInit_EncryptedPacket packet = (PacketInit_EncryptedPacket)(arguments[0]);
|
||||||
|
callback.invoke(packet.encryptedBlock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PacketInit_ServerResponse
|
||||||
|
{
|
||||||
|
public boolean succeeded;
|
||||||
|
public String reason;
|
||||||
|
|
||||||
|
public PacketInit_ServerResponse(boolean succeeded, String reason)
|
||||||
|
{
|
||||||
|
this.succeeded = succeeded;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet1_ClientSendsHello
|
||||||
|
{
|
||||||
|
public String user;
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
public Packet1_ClientSendsHello (String user, String version)
|
||||||
|
{
|
||||||
|
this.user = user;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet2_ServerSendSalt
|
||||||
|
{
|
||||||
|
public byte[] salt;
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
public Packet2_ServerSendSalt (String version, byte[] salt)
|
||||||
|
{
|
||||||
|
this.salt = salt;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getSalt ()
|
||||||
|
{
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet3_ClientSendPublicKey
|
||||||
|
{
|
||||||
|
public byte[] publicKey;
|
||||||
|
|
||||||
|
public Packet3_ClientSendPublicKey (byte[] publicKey)
|
||||||
|
{
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPublicKey ()
|
||||||
|
{
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet4_ServerSendPublicKey
|
||||||
|
{
|
||||||
|
public byte[] publicKey;
|
||||||
|
|
||||||
|
public Packet4_ServerSendPublicKey (BigInteger publicKey)
|
||||||
|
{
|
||||||
|
this.publicKey = publicKey.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPublicKey ()
|
||||||
|
{
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet5_ClientSendEvidence
|
||||||
|
{
|
||||||
|
public byte[] evidence;
|
||||||
|
|
||||||
|
public Packet5_ClientSendEvidence (byte[] evidence)
|
||||||
|
{
|
||||||
|
this.evidence = evidence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEvidence ()
|
||||||
|
{
|
||||||
|
return evidence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Packet6_ServerSendEvidenceAndPayload
|
||||||
|
{
|
||||||
|
public byte[] evidence;
|
||||||
|
|
||||||
|
public Packet6_ServerSendEvidenceAndPayload (BigInteger evidence)
|
||||||
|
{
|
||||||
|
this.evidence = evidence.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEvidence ()
|
||||||
|
{
|
||||||
|
return evidence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
java/core/src/core/srp/SRPSession.java
Normal file
43
java/core/src/core/srp/SRPSession.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp;
|
||||||
|
|
||||||
|
import core.crypt.Cryptor;
|
||||||
|
import core.crypt.CryptorAES;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
|
||||||
|
|
||||||
|
public class SRPSession
|
||||||
|
{
|
||||||
|
protected byte[] sessionKey;
|
||||||
|
|
||||||
|
public byte[] streamDecrypt (byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cryptor cryptor = new CryptorAES(sessionKey);
|
||||||
|
return cryptor.decrypt(bytes);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] streamEncrypt (byte[] bytes) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cryptor cryptor = new CryptorAES(sessionKey);
|
||||||
|
return cryptor.encrypt(bytes);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
java/core/src/core/srp/client/SRPClient.java
Normal file
91
java/core/src/core/srp/client/SRPClient.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.client;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import com.jordanzimmerman.SRPClientSession;
|
||||||
|
import com.jordanzimmerman.SRPFactory;
|
||||||
|
import com.jordanzimmerman.SRPVerifier;
|
||||||
|
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
import core.callbacks.JSONSerialize;
|
||||||
|
import core.callbacks.IoSend;
|
||||||
|
import core.crypt.KeyPairFromPassword;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.io.IoChain;
|
||||||
|
import core.srp.SRPPackets;
|
||||||
|
import core.srp.SRPSession;
|
||||||
|
|
||||||
|
public class SRPClient extends SRPSession
|
||||||
|
{
|
||||||
|
static { SRPPackets.register(); }
|
||||||
|
|
||||||
|
SRPFactory factory;
|
||||||
|
SRPClientAsync session;
|
||||||
|
|
||||||
|
public SRPClient (byte[] password)
|
||||||
|
{
|
||||||
|
session = new SRPClientAsync(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SRPVerifier createVerifierFromKeyPair (KeyPairFromPassword keyPair) throws CryptoException
|
||||||
|
{
|
||||||
|
SRPFactory factory = SRPFactory.getInstance();
|
||||||
|
SRPVerifier verifier = factory.makeVerifier(keyPair.getVerifier());
|
||||||
|
|
||||||
|
return verifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRPPackets.Packet1_ClientSendsHello step1_generateHello (String user, String version)
|
||||||
|
{
|
||||||
|
return new SRPPackets.Packet1_ClientSendsHello(user, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback step2_generatePublicKey_send_ (SRPPackets.Packet2_ServerSendSalt packet, IoChain sender)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
session.setSalt_(packet.getSalt())
|
||||||
|
.addCallback(
|
||||||
|
new CallbackDefault() {
|
||||||
|
public void onSuccess(Object...arguments) {
|
||||||
|
next(new SRPPackets.Packet3_ClientSendPublicKey(session.getPublicKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.addCallback(new JSONSerialize())
|
||||||
|
.addCallback(new IoSend(sender));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback step3_generateEvidenceUsingServerProvidedInputs_send (SRPPackets.Packet4_ServerSendPublicKey packet, IoChain sender) throws CryptoException
|
||||||
|
{
|
||||||
|
return
|
||||||
|
session.setServerPublicKey_(packet.getPublicKey())
|
||||||
|
.addCallback(
|
||||||
|
new CallbackDefault() {
|
||||||
|
public void onSuccess(Object...arguments) {
|
||||||
|
next(new SRPPackets.Packet5_ClientSendEvidence(session.getEvidenceValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.addCallback(new JSONSerialize())
|
||||||
|
.addCallback(new IoSend(sender));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback step4_validateServerEvidence (SRPPackets.Packet6_ServerSendEvidenceAndPayload packet) throws CryptoException
|
||||||
|
{
|
||||||
|
return
|
||||||
|
session.validateServerEvidenceValue_M2_(packet.getEvidence())
|
||||||
|
.addCallback(
|
||||||
|
new CallbackDefault() {
|
||||||
|
public void onSuccess(Object...arguments) {
|
||||||
|
sessionKey = session.getSessionKey();
|
||||||
|
next(sessionKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
java/core/src/core/srp/client/SRPClientAsync.java
Normal file
71
java/core/src/core/srp/client/SRPClientAsync.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.client;
|
||||||
|
|
||||||
|
import com.jordanzimmerman.SRPClientSession;
|
||||||
|
import com.jordanzimmerman.SRPFactory;
|
||||||
|
|
||||||
|
import core.util.Base64;
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
|
||||||
|
public class SRPClientAsync
|
||||||
|
{
|
||||||
|
SRPClientSession key;
|
||||||
|
|
||||||
|
public SRPClientAsync (byte[] password)
|
||||||
|
{
|
||||||
|
key = SRPFactory.getInstance().newClientSession(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback setSalt_(byte[] bs)
|
||||||
|
{
|
||||||
|
return new CallbackDefault(bs)
|
||||||
|
{
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
key.setSalt_s((byte[])V(0));
|
||||||
|
callback.invoke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback setServerPublicKey_(byte[] publicKey)
|
||||||
|
{
|
||||||
|
return new CallbackDefault(publicKey)
|
||||||
|
{
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
key.setServerPublicKey_B((byte[])V(0));
|
||||||
|
callback.invoke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback validateServerEvidenceValue_M2_(byte[] evidence)
|
||||||
|
{
|
||||||
|
return new CallbackDefault(evidence)
|
||||||
|
{
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
key.validateServerEvidenceValue_M2((byte[])V(0));
|
||||||
|
callback.invoke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getSessionKey()
|
||||||
|
{
|
||||||
|
return key.getSessionKey_K();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPublicKey()
|
||||||
|
{
|
||||||
|
return key.getPublicKey_A_();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEvidenceValue()
|
||||||
|
{
|
||||||
|
return key.getEvidenceValue_M1_();
|
||||||
|
}
|
||||||
|
}
|
10
java/core/src/core/srp/client/SRPClientListener.java
Normal file
10
java/core/src/core/srp/client/SRPClientListener.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.client;
|
||||||
|
|
||||||
|
public interface SRPClientListener {
|
||||||
|
public void onSRPStep (String stepName);
|
||||||
|
}
|
93
java/core/src/core/srp/client/SRPClientUserSession.java
Normal file
93
java/core/src/core/srp/client/SRPClientUserSession.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.client;
|
||||||
|
|
||||||
|
import core.callbacks.IoOpen;
|
||||||
|
import core.constants.ConstantsVersion;
|
||||||
|
import core.crypt.KeyPairFromPassword;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.io.IoChain;
|
||||||
|
import core.srp.SRPPackets;
|
||||||
|
import core.util.SimpleSerializer;
|
||||||
|
|
||||||
|
public class SRPClientUserSession extends IoChain
|
||||||
|
{
|
||||||
|
String user;
|
||||||
|
KeyPairFromPassword keyPair;
|
||||||
|
SRPClient srp;
|
||||||
|
SRPClientListener listener;
|
||||||
|
int step;
|
||||||
|
|
||||||
|
public SRPClientUserSession (String user, KeyPairFromPassword keyPair, IoChain sender, SRPClientListener listener) throws CryptoException
|
||||||
|
{
|
||||||
|
super(sender);
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
this.keyPair = keyPair;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open () throws Exception
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("H");
|
||||||
|
|
||||||
|
step = 0;
|
||||||
|
this.srp = new SRPClient(keyPair.getVerifier());
|
||||||
|
sender.send(SimpleSerializer.serialize(new SRPPackets.Packet1_ClientSendsHello(user, ConstantsVersion.LOGIN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReceive(byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
switch (step++)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("" + step);
|
||||||
|
|
||||||
|
SRPPackets.Packet2_ServerSendSalt in = SimpleSerializer.deserialize(bytes);
|
||||||
|
srp.step2_generatePublicKey_send_(in, sender).invoke();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("" + step);
|
||||||
|
|
||||||
|
SRPPackets.Packet4_ServerSendPublicKey in = SimpleSerializer.deserialize(bytes);
|
||||||
|
srp.step3_generateEvidenceUsingServerProvidedInputs_send(in, sender).invoke();
|
||||||
|
} break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("" + step);
|
||||||
|
|
||||||
|
SRPPackets.Packet6_ServerSendEvidenceAndPayload in = SimpleSerializer.deserialize(bytes);
|
||||||
|
srp.step4_validateServerEvidence(in).addCallback(new IoOpen(receiver)).invoke();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("R");
|
||||||
|
|
||||||
|
super.onReceive(srp.streamDecrypt(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSRPStep("S");
|
||||||
|
|
||||||
|
sender.send(srp.streamEncrypt(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
77
java/core/src/core/srp/server/SRPServer.java
Normal file
77
java/core/src/core/srp/server/SRPServer.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.server;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.bc.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
|
||||||
|
import com.jordanzimmerman.SRPFactory;
|
||||||
|
import com.jordanzimmerman.SRPServerSession;
|
||||||
|
import com.jordanzimmerman.SRPVerifier;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.srp.SRPPackets;
|
||||||
|
import core.srp.SRPSession;
|
||||||
|
import core.srp.SRPPackets.Packet2_ServerSendSalt;
|
||||||
|
import core.srp.SRPPackets.Packet3_ClientSendPublicKey;
|
||||||
|
import core.srp.SRPPackets.Packet4_ServerSendPublicKey;
|
||||||
|
import core.srp.SRPPackets.Packet5_ClientSendEvidence;
|
||||||
|
import core.srp.SRPPackets.Packet6_ServerSendEvidenceAndPayload;
|
||||||
|
|
||||||
|
public class SRPServer extends SRPSession
|
||||||
|
{
|
||||||
|
static { SRPPackets.register(); }
|
||||||
|
|
||||||
|
SRPFactory factory;
|
||||||
|
SRPServerSession session;
|
||||||
|
|
||||||
|
public SRPServer ()
|
||||||
|
{
|
||||||
|
factory = SRPFactory.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRPPackets.Packet2_ServerSendSalt step1_getSalt_send (String version, BigInteger verifier, BigInteger salt)
|
||||||
|
{
|
||||||
|
session = factory.newServerSession(new SRPVerifier (verifier, salt));
|
||||||
|
return new SRPPackets.Packet2_ServerSendSalt(version, session.getVerifier().salt_s.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRPPackets.Packet4_ServerSendPublicKey step2_receivePublicKey_generatePublicKey_send (SRPPackets.Packet3_ClientSendPublicKey packet) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
session.setClientPublicKey_A(packet.getPublicKey());
|
||||||
|
return new SRPPackets.Packet4_ServerSendPublicKey(session.getPublicKey_B());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRPPackets.Packet6_ServerSendEvidenceAndPayload step3_validateClientEvidence_generateEvidence_send (SRPPackets.Packet5_ClientSendEvidence packet) throws CryptoException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
session.computeCommonValue_S();
|
||||||
|
session.validateClientEvidenceValue_M1(packet.getEvidence());
|
||||||
|
|
||||||
|
sessionKey = session.getSessionKey_K();
|
||||||
|
|
||||||
|
return new SRPPackets.Packet6_ServerSendEvidenceAndPayload(session.getEvidenceValue_M2());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new CryptoException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
java/core/src/core/srp/server/SRPServerUserSession.java
Normal file
177
java/core/src/core/srp/server/SRPServerUserSession.java
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.server;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import core.client.messages.ClientMessagesSerializerJSON;
|
||||||
|
import core.crypt.CryptorRSAAES;
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.exceptions.PublicMessageException;
|
||||||
|
import core.io.IoChain;
|
||||||
|
import core.srp.SRPPackets;
|
||||||
|
import core.srp.SRPPackets.PacketInit_ClientTestCreate;
|
||||||
|
import core.util.LogOut;
|
||||||
|
import core.util.SimpleSerializer;
|
||||||
|
import core.util.Strings;
|
||||||
|
import core.util.Triple;
|
||||||
|
|
||||||
|
|
||||||
|
public class SRPServerUserSession extends IoChain
|
||||||
|
{
|
||||||
|
static { SRPPackets.register(); ClientMessagesSerializerJSON.register(); }
|
||||||
|
|
||||||
|
LogOut log = new LogOut(SRPServerUserSession.class);
|
||||||
|
|
||||||
|
CryptorRSAAES cryptorRSA;
|
||||||
|
boolean noMoreRoomForUsers = false;
|
||||||
|
String userName;
|
||||||
|
SRPServer srp = new SRPServer();
|
||||||
|
int step = 0;
|
||||||
|
SRPServerUserSessionDb db;
|
||||||
|
|
||||||
|
public SRPServerUserSession (CryptorRSAAES cryptorRSA, SRPServerUserSessionDb db, IoChain session)
|
||||||
|
{
|
||||||
|
super(session);
|
||||||
|
|
||||||
|
this.db = db;
|
||||||
|
this.cryptorRSA = cryptorRSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName ()
|
||||||
|
{
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive (byte[] bytes) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (step == 0)
|
||||||
|
{
|
||||||
|
Object object = SimpleSerializer.deserialize(bytes);
|
||||||
|
if (object instanceof SRPPackets.PacketInit_EncryptedPacket)
|
||||||
|
{
|
||||||
|
step = -1;
|
||||||
|
|
||||||
|
SRPPackets.PacketInit_EncryptedPacket
|
||||||
|
block = (SRPPackets.PacketInit_EncryptedPacket)object;
|
||||||
|
|
||||||
|
Object packet = SimpleSerializer.deserialize(cryptorRSA.decrypt(block.encryptedBlock));
|
||||||
|
|
||||||
|
if (packet instanceof SRPPackets.PacketInit_ClientPreAutheticationInitialization)
|
||||||
|
{
|
||||||
|
step_init((SRPPackets.PacketInit_ClientPreAutheticationInitialization)packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (packet instanceof SRPPackets.PacketInit_ClientTestCreate)
|
||||||
|
{
|
||||||
|
step_testcreate((SRPPackets.PacketInit_ClientTestCreate)packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (step++)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
SRPPackets.Packet1_ClientSendsHello packet = SimpleSerializer.deserialize(bytes);
|
||||||
|
this.userName = packet.user;
|
||||||
|
db.rateLimitFailure(userName);
|
||||||
|
|
||||||
|
Triple<String, BigInteger, BigInteger> vvs = db.getUserVVS(packet.user);
|
||||||
|
sender.send(SimpleSerializer.serialize(
|
||||||
|
srp.step1_getSalt_send(vvs.first, vvs.second, vvs.third)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
SRPPackets.Packet3_ClientSendPublicKey packet = SimpleSerializer.deserialize(bytes);
|
||||||
|
sender.send(SimpleSerializer.serialize(srp.step2_receivePublicKey_generatePublicKey_send(packet)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
SRPPackets.Packet5_ClientSendEvidence packet = SimpleSerializer.deserialize(bytes);
|
||||||
|
SRPPackets.Packet6_ServerSendEvidenceAndPayload out =
|
||||||
|
srp.step3_validateClientEvidence_generateEvidence_send(packet);
|
||||||
|
|
||||||
|
sender.send(SimpleSerializer.serialize(out));
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
super.onReceive(srp.streamDecrypt(bytes));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (CryptoException e)
|
||||||
|
{
|
||||||
|
db.markFailure(userName);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (PublicMessageException e)
|
||||||
|
{
|
||||||
|
db.markFailure(userName);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
db.markFailure(userName);
|
||||||
|
throw new CryptoException (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void step_testcreate(PacketInit_ClientTestCreate packet) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
db.testCreate (packet.version, packet.user);
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(true, null)));
|
||||||
|
}
|
||||||
|
catch (PublicMessageException e)
|
||||||
|
{
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, e.message)));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, null)));
|
||||||
|
}
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void step_init (SRPPackets.PacketInit_ClientPreAutheticationInitialization packet) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
db.createUser (packet.version, packet.user, new BigInteger(packet.v), new BigInteger(packet.s), packet.extra);
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(true, null)));
|
||||||
|
}
|
||||||
|
catch (PublicMessageException e)
|
||||||
|
{
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, e.message)));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
sender.send (SimpleSerializer.serialize(new SRPPackets.PacketInit_ServerResponse(false, null)));
|
||||||
|
}
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(byte[] packet) throws Exception
|
||||||
|
{
|
||||||
|
sender.send(srp.streamEncrypt(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
java/core/src/core/srp/server/SRPServerUserSessionDb.java
Normal file
23
java/core/src/core/srp/server/SRPServerUserSessionDb.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.server;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import core.util.Pair;
|
||||||
|
import core.util.Triple;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SRPServerUserSessionDb
|
||||||
|
{
|
||||||
|
public void rateLimitFailure (String userName) throws Exception;
|
||||||
|
public void markFailure (String userName) throws Exception;
|
||||||
|
|
||||||
|
public Triple<String, BigInteger, BigInteger> getUserVVS (String userName) throws Exception;
|
||||||
|
|
||||||
|
public void testCreate (String version, String userName) throws Exception;
|
||||||
|
public void createUser (String version, String userName, BigInteger v, BigInteger s, byte[] extra) throws Exception;
|
||||||
|
}
|
57
java/core/src/core/srp/test/PBETest.java
Normal file
57
java/core/src/core/srp/test/PBETest.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.srp.test;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import core.exceptions.CryptoException;
|
||||||
|
import core.crypt.KeyPairFromPassword;
|
||||||
|
import core.crypt.KeyPairFromPasswordCryptor;
|
||||||
|
import core.crypt.PBE;
|
||||||
|
import core.util.Streams;
|
||||||
|
|
||||||
|
|
||||||
|
public class PBETest
|
||||||
|
{
|
||||||
|
public static void main (String[] args) throws CryptoException, IOException
|
||||||
|
{
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
String password = "TESTPASSWORD";
|
||||||
|
|
||||||
|
String s = "I am a string which is not to short not to long. I really should be much much larger. " +
|
||||||
|
"but what can I do. I wonder, in reality this string would be a very long random number. ";
|
||||||
|
|
||||||
|
for (int i=0; i<50; ++i)
|
||||||
|
s += BigInteger.valueOf(Math.abs(random.nextLong())).toString(32);
|
||||||
|
|
||||||
|
KeyPairFromPassword keyPair = new KeyPairFromPassword(password);
|
||||||
|
KeyPairFromPasswordCryptor cryptor = new KeyPairFromPasswordCryptor(keyPair);
|
||||||
|
byte[] verifier = keyPair.getVerifier();
|
||||||
|
|
||||||
|
System.out.println(new BigInteger(verifier));
|
||||||
|
|
||||||
|
byte[] e = cryptor.encrypt(s.getBytes());
|
||||||
|
|
||||||
|
FileOutputStream fe = new FileOutputStream("PBETest.enc");
|
||||||
|
fe.write(e);
|
||||||
|
fe.flush();
|
||||||
|
|
||||||
|
FileOutputStream fp = new FileOutputStream("PBETest.plain");
|
||||||
|
fp.write(e);
|
||||||
|
fp.flush();
|
||||||
|
|
||||||
|
byte[] in = Streams.readFullyBytes(new FileInputStream("PBETest.enc"));
|
||||||
|
String match = new String(cryptor.decrypt(in));
|
||||||
|
|
||||||
|
if (match.equals(s))
|
||||||
|
System.out.println("decryption succeeded");
|
||||||
|
}
|
||||||
|
}
|
31
java/core/src/core/swing/CheckListener.java
Normal file
31
java/core/src/core/swing/CheckListener.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
|
public class CheckListener implements DocumentListener
|
||||||
|
{
|
||||||
|
Checker checker;
|
||||||
|
|
||||||
|
public CheckListener (Checker checker)
|
||||||
|
{
|
||||||
|
this.checker = checker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onChange ()
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() { checker.onCheck(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changedUpdate(DocumentEvent e) { onChange(); }
|
||||||
|
public void insertUpdate(DocumentEvent e) { onChange(); }
|
||||||
|
public void removeUpdate(DocumentEvent e) { onChange(); }
|
||||||
|
}
|
11
java/core/src/core/swing/Checker.java
Normal file
11
java/core/src/core/swing/Checker.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
public interface Checker
|
||||||
|
{
|
||||||
|
public void onCheck ();
|
||||||
|
}
|
16
java/core/src/core/swing/DimensionCalculator.java
Normal file
16
java/core/src/core/swing/DimensionCalculator.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
|
||||||
|
public class DimensionCalculator
|
||||||
|
{
|
||||||
|
public Dimension calculate (Dimension dimension)
|
||||||
|
{
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
}
|
38
java/core/src/core/swing/FileFilterStandard.java
Normal file
38
java/core/src/core/swing/FileFilterStandard.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
|
||||||
|
public class FileFilterStandard extends FileFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
String name, extension;
|
||||||
|
|
||||||
|
public FileFilterStandard(String name, String extension)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.extension = extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean accept(File f)
|
||||||
|
{
|
||||||
|
if (f.isDirectory())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (f.getPath().toLowerCase().endsWith(extension));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The description of this filter
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
81
java/core/src/core/swing/RedirectStreams.java
Normal file
81
java/core/src/core/swing/RedirectStreams.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
import java.awt.TextArea;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import javax.swing.JTextArea;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
public class RedirectStreams
|
||||||
|
{
|
||||||
|
JTextArea textArea;
|
||||||
|
|
||||||
|
PrintStream savedOutput;
|
||||||
|
PrintStream savedError;
|
||||||
|
PrintStream out;
|
||||||
|
|
||||||
|
public RedirectStreams(JTextArea textArea)
|
||||||
|
{
|
||||||
|
this.textArea = textArea;
|
||||||
|
OutputStream os =
|
||||||
|
new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException
|
||||||
|
{
|
||||||
|
updateTextArea(String.valueOf((char) b));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException
|
||||||
|
{
|
||||||
|
updateTextArea(new String(b, off, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) throws IOException
|
||||||
|
{
|
||||||
|
write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
out = new PrintStream(os, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTextArea(final String text)
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
textArea.append(text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redirectSystem()
|
||||||
|
{
|
||||||
|
savedOutput = System.out;
|
||||||
|
savedError = System.err;
|
||||||
|
|
||||||
|
System.setOut(out);
|
||||||
|
System.setErr(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrintStream getOut ()
|
||||||
|
{
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreSystem ()
|
||||||
|
{
|
||||||
|
System.setOut(savedOutput);
|
||||||
|
System.setErr(savedError);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
java/core/src/core/swing/SpringLayoutSize.java
Normal file
72
java/core/src/core/swing/SpringLayoutSize.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.swing;
|
||||||
|
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
|
||||||
|
import javax.swing.SpringLayout;
|
||||||
|
|
||||||
|
public class SpringLayoutSize extends SpringLayout
|
||||||
|
{
|
||||||
|
Dimension dimension;
|
||||||
|
DimensionCalculator dimensionCalculator;
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
public SpringLayoutSize (int depth, Dimension dimension, DimensionCalculator dimensionCalculator)
|
||||||
|
{
|
||||||
|
this.dimension = dimension;
|
||||||
|
this.depth = depth;
|
||||||
|
this.dimensionCalculator = dimensionCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpringLayoutSize (int depth, Dimension dimension)
|
||||||
|
{
|
||||||
|
this(depth, dimension, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Container getNestedParent(Container parent)
|
||||||
|
{
|
||||||
|
for (int i=1; i<depth; ++i)
|
||||||
|
parent = parent.getParent();
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension calculateDimension (Container parent)
|
||||||
|
{
|
||||||
|
Container nestedParent = getNestedParent (parent);
|
||||||
|
|
||||||
|
Dimension result =
|
||||||
|
new Dimension (
|
||||||
|
dimension.width > 0 ? dimension.width : nestedParent.getSize().width,
|
||||||
|
dimension.height > 0 ? dimension.height : nestedParent.getSize().height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dimensionCalculator != null)
|
||||||
|
result = dimensionCalculator.calculate(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension maximumLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
return calculateDimension(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension minimumLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
return calculateDimension(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension preferredLayoutSize(Container parent)
|
||||||
|
{
|
||||||
|
return calculateDimension(parent);
|
||||||
|
}
|
||||||
|
}
|
73
java/core/src/core/util/Arrays.java
Normal file
73
java/core/src/core/util/Arrays.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Arrays
|
||||||
|
{
|
||||||
|
public static <T> T firstOrNull (T[] t)
|
||||||
|
{
|
||||||
|
if (t != null && t.length > 0)
|
||||||
|
return t[0];
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] generate (int length, int j)
|
||||||
|
{
|
||||||
|
byte[] v = new byte[length];
|
||||||
|
for (int i=0; i<length; ++i)
|
||||||
|
v[i]=(byte)j;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] concat (byte[]... arrays)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
for (byte[] array : arrays)
|
||||||
|
length += array.length;
|
||||||
|
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
for (byte[] array : arrays)
|
||||||
|
{
|
||||||
|
for (byte b : array)
|
||||||
|
result[i++] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] copyOf(byte[] src, int l)
|
||||||
|
{
|
||||||
|
return copyOf(src, 0, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copyFromTo(byte[] src, int srcOff, byte[] dst, int dstOff, int l)
|
||||||
|
{
|
||||||
|
for (int i=0; i<l; ++i)
|
||||||
|
dst[i+dstOff] = src[i+srcOff];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copyFromTo(byte[] src, byte[] dst, int l)
|
||||||
|
{
|
||||||
|
copyFromTo(src,0, dst,0, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] copyOf(byte[] src, int offset, int l)
|
||||||
|
{
|
||||||
|
byte[] result = new byte[l];
|
||||||
|
|
||||||
|
for (int i=0; i<l; ++i)
|
||||||
|
result[i] = src[offset + i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
58
java/core/src/core/util/Base16.java
Normal file
58
java/core/src/core/util/Base16.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
public class Base16
|
||||||
|
{
|
||||||
|
static String decoder = "0123456789abcdef";
|
||||||
|
static byte[] encoder = null;
|
||||||
|
|
||||||
|
static void initialize ()
|
||||||
|
{
|
||||||
|
if (encoder != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
encoder = new byte[0xFF];
|
||||||
|
for (int i=0; i<decoder.length(); ++i)
|
||||||
|
encoder[decoder.charAt(i)] = (byte)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decode (String value)
|
||||||
|
{
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
byte[] bytes = new byte[value.length() / 2];
|
||||||
|
|
||||||
|
int i=0, j=0;
|
||||||
|
while (i<value.length())
|
||||||
|
{
|
||||||
|
int nibbleHi = (int)encoder[(int)value.charAt(i++)];
|
||||||
|
int nibbleLo = (int)encoder[(int)value.charAt(i++)];
|
||||||
|
|
||||||
|
bytes[j++] = (byte) ((nibbleHi << 4) | (nibbleLo));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encode (byte[] bytes)
|
||||||
|
{
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
while (i<bytes.length)
|
||||||
|
{
|
||||||
|
int b = bytes[i++] & 0xFF;
|
||||||
|
int nibbleLo = b & 0x0F;
|
||||||
|
int nibbleHi = b >> 4;
|
||||||
|
|
||||||
|
result += decoder.charAt(nibbleHi);
|
||||||
|
result += decoder.charAt(nibbleLo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
68
java/core/src/core/util/Base64.java
Normal file
68
java/core/src/core/util/Base64.java
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import core.callback.Callback;
|
||||||
|
import core.callback.CallbackDefault;
|
||||||
|
|
||||||
|
public class Base64
|
||||||
|
{
|
||||||
|
public static String encode(byte[] bytes)
|
||||||
|
{
|
||||||
|
return Strings.toString(org.bc.util.encoders.Base64.encode(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decode(String b64)
|
||||||
|
{
|
||||||
|
return org.bc.util.encoders.Base64.decode(Strings.toBytes(b64));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encodeBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return org.bc.util.encoders.Base64.encode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decodeBytes(byte[] b64)
|
||||||
|
{
|
||||||
|
return org.bc.util.encoders.Base64.decode(b64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback decode_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Base64.decode((String)arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback encode_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Base64.encode((byte[])arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback decodeBytes_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Base64.decodeBytes((byte[])arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Callback encodeBytes_()
|
||||||
|
{
|
||||||
|
return new CallbackDefault() {
|
||||||
|
public void onSuccess(Object... arguments) throws Exception {
|
||||||
|
next(Base64.encodeBytes((byte[])arguments[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
20
java/core/src/core/util/Block.java
Normal file
20
java/core/src/core/util/Block.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Block implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public byte[] bytes;
|
||||||
|
|
||||||
|
public Block (byte[] bytes)
|
||||||
|
{
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
}
|
15
java/core/src/core/util/CallSingle.java
Normal file
15
java/core/src/core/util/CallSingle.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import org.timepedia.exporter.client.Export;
|
||||||
|
import org.timepedia.exporter.client.Exportable;
|
||||||
|
|
||||||
|
@Export
|
||||||
|
public interface CallSingle<T, V> extends Exportable
|
||||||
|
{
|
||||||
|
public T invoke(V v) throws Exception;
|
||||||
|
}
|
24
java/core/src/core/util/CallSingleWithVariables.java
Normal file
24
java/core/src/core/util/CallSingleWithVariables.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import core.util.CallSingle;
|
||||||
|
|
||||||
|
abstract class CallSingleWithVariables<T,V> implements CallSingle<T,V>
|
||||||
|
{
|
||||||
|
protected Object[] v;
|
||||||
|
|
||||||
|
public CallSingleWithVariables(Object... v)
|
||||||
|
{
|
||||||
|
this.v = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T V(int i)
|
||||||
|
{
|
||||||
|
return (T)v[i];
|
||||||
|
}
|
||||||
|
}
|
20
java/core/src/core/util/Characters.java
Normal file
20
java/core/src/core/util/Characters.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
public class Characters {
|
||||||
|
|
||||||
|
public static boolean isWhitespace(char c)
|
||||||
|
{
|
||||||
|
return " \t\n\r".indexOf(c)!=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNumber(char c)
|
||||||
|
{
|
||||||
|
return "0123456789".indexOf(c)!=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
809
java/core/src/core/util/CircularByteBuffer.java
Normal file
809
java/core/src/core/util/CircularByteBuffer.java
Normal file
@ -0,0 +1,809 @@
|
|||||||
|
/*
|
||||||
|
* Circular Byte Buffer
|
||||||
|
* Copyright (C) 2002-2010 Stephen Ostermiller
|
||||||
|
* http://ostermiller.org/contact.pl?regarding=Java+Utilities
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* See LICENSE.txt for details.
|
||||||
|
*/
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the Circular Buffer producer/consumer model for bytes.
|
||||||
|
* More information about this class is available from <a target="_top" href=
|
||||||
|
* "http://ostermiller.org/utils/CircularByteBuffer.html">ostermiller.org</a>.
|
||||||
|
* <p>
|
||||||
|
* Using this class is a simpler alternative to using a PipedInputStream
|
||||||
|
* and a PipedOutputStream. PipedInputStreams and PipedOutputStreams don't support the
|
||||||
|
* mark operation, don't allow you to control buffer sizes that they use,
|
||||||
|
* and have a more complicated API that requires instantiating two
|
||||||
|
* classes and connecting them.
|
||||||
|
* <p>
|
||||||
|
* This class is thread safe.
|
||||||
|
*
|
||||||
|
* @see CircularCharBuffer
|
||||||
|
* @see CircularObjectBuffer
|
||||||
|
*
|
||||||
|
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public class CircularByteBuffer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default size for a circular byte buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private final static int DEFAULT_SIZE = 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer that will grow as things are added.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public final static int INFINITE_SIZE = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The circular buffer.
|
||||||
|
* <p>
|
||||||
|
* The actual capacity of the buffer is one less than the actual length
|
||||||
|
* of the buffer so that an empty and a full buffer can be
|
||||||
|
* distinguished. An empty buffer will have the markPostion and the
|
||||||
|
* writePosition equal to each other. A full buffer will have
|
||||||
|
* the writePosition one less than the markPostion.
|
||||||
|
* <p>
|
||||||
|
* There are three important indexes into the buffer:
|
||||||
|
* The readPosition, the writePosition, and the markPosition.
|
||||||
|
* If the InputStream has never been marked, the readPosition and
|
||||||
|
* the markPosition should always be the same. The bytes
|
||||||
|
* available to be read go from the readPosition to the writePosition,
|
||||||
|
* wrapping around the end of the buffer. The space available for writing
|
||||||
|
* goes from the write position to one less than the markPosition,
|
||||||
|
* wrapping around the end of the buffer. The bytes that have
|
||||||
|
* been saved to support a reset() of the InputStream go from markPosition
|
||||||
|
* to readPosition, wrapping around the end of the buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected byte[] buffer;
|
||||||
|
/**
|
||||||
|
* Index of the first byte available to be read.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected volatile int readPosition = 0;
|
||||||
|
/**
|
||||||
|
* Index of the first byte available to be written.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected volatile int writePosition = 0;
|
||||||
|
/**
|
||||||
|
* Index of the first saved byte. (To support stream marking.)
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected volatile int markPosition = 0;
|
||||||
|
/**
|
||||||
|
* Number of bytes that have to be saved
|
||||||
|
* to support mark() and reset() on the InputStream.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected volatile int markSize = 0;
|
||||||
|
/**
|
||||||
|
* If this buffer is infinite (should resize itself when full)
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected volatile boolean infinite = false;
|
||||||
|
/**
|
||||||
|
* True if a write to a full buffer should block until the buffer
|
||||||
|
* has room, false if the write method should throw an IOException
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected boolean blockingWrite = true;
|
||||||
|
/**
|
||||||
|
* The InputStream that can empty this buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected InputStream in = new CircularByteBufferInputStream();
|
||||||
|
/**
|
||||||
|
* true if the close() method has been called on the InputStream
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected boolean inputStreamClosed = false;
|
||||||
|
/**
|
||||||
|
* The OutputStream that can fill this buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected OutputStream out = new CircularByteBufferOutputStream();
|
||||||
|
/**
|
||||||
|
* true if the close() method has been called on the OutputStream
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected boolean outputStreamClosed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make this buffer ready for reuse. The contents of the buffer
|
||||||
|
* will be cleared and the streams associated with this buffer
|
||||||
|
* will be reopened if they had been closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public void clear(){
|
||||||
|
synchronized (this){
|
||||||
|
readPosition = 0;
|
||||||
|
writePosition = 0;
|
||||||
|
markPosition = 0;
|
||||||
|
outputStreamClosed = false;
|
||||||
|
inputStreamClosed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a OutputStream that can be used to fill
|
||||||
|
* this buffer.
|
||||||
|
* <p>
|
||||||
|
* Write methods may throw a BufferOverflowException if
|
||||||
|
* the buffer is not large enough. A large enough buffer
|
||||||
|
* size must be chosen so that this does not happen or
|
||||||
|
* the caller must be prepared to catch the exception and
|
||||||
|
* try again once part of the buffer has been consumed.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return the producer for this buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public OutputStream getOutputStream(){
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a InputStream that can be used to empty
|
||||||
|
* this buffer.
|
||||||
|
* <p>
|
||||||
|
* This InputStream supports marks at the expense
|
||||||
|
* of the buffer size.
|
||||||
|
*
|
||||||
|
* @return the consumer for this buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream(){
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of bytes that are available to be read.
|
||||||
|
* <p>
|
||||||
|
* Note that the number of bytes available plus
|
||||||
|
* the number of bytes free may not add up to the
|
||||||
|
* capacity of this buffer, as the buffer may reserve some
|
||||||
|
* space for other purposes.
|
||||||
|
*
|
||||||
|
* @return the size in bytes of this buffer
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public int getAvailable(){
|
||||||
|
synchronized (this){
|
||||||
|
return available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes this buffer has free for
|
||||||
|
* writing.
|
||||||
|
* <p>
|
||||||
|
* Note that the number of bytes available plus
|
||||||
|
* the number of bytes free may not add up to the
|
||||||
|
* capacity of this buffer, as the buffer may reserve some
|
||||||
|
* space for other purposes.
|
||||||
|
*
|
||||||
|
* @return the available space in bytes of this buffer
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public int getSpaceLeft(){
|
||||||
|
synchronized (this){
|
||||||
|
return spaceLeft();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the capacity of this buffer.
|
||||||
|
* <p>
|
||||||
|
* Note that the number of bytes available plus
|
||||||
|
* the number of bytes free may not add up to the
|
||||||
|
* capacity of this buffer, as the buffer may reserve some
|
||||||
|
* space for other purposes.
|
||||||
|
*
|
||||||
|
* @return the size in bytes of this buffer
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public int getSize(){
|
||||||
|
synchronized (this){
|
||||||
|
return buffer.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* double the size of the buffer
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private void resize(){
|
||||||
|
byte[] newBuffer = new byte[buffer.length * 2];
|
||||||
|
int marked = marked();
|
||||||
|
int available = available();
|
||||||
|
if (markPosition <= writePosition){
|
||||||
|
// any space between the mark and
|
||||||
|
// the first write needs to be saved.
|
||||||
|
// In this case it is all in one piece.
|
||||||
|
int length = writePosition - markPosition;
|
||||||
|
System.arraycopy(buffer, markPosition, newBuffer, 0, length);
|
||||||
|
} else {
|
||||||
|
int length1 = buffer.length - markPosition;
|
||||||
|
System.arraycopy(buffer, markPosition, newBuffer, 0, length1);
|
||||||
|
int length2 = writePosition;
|
||||||
|
System.arraycopy(buffer, 0, newBuffer, length1, length2);
|
||||||
|
}
|
||||||
|
buffer = newBuffer;
|
||||||
|
markPosition = 0;
|
||||||
|
readPosition = marked;
|
||||||
|
writePosition = marked + available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Space available in the buffer which can be written.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private int spaceLeft(){
|
||||||
|
if (writePosition < markPosition){
|
||||||
|
// any space between the first write and
|
||||||
|
// the mark except one byte is available.
|
||||||
|
// In this case it is all in one piece.
|
||||||
|
return (markPosition - writePosition - 1);
|
||||||
|
}
|
||||||
|
// space at the beginning and end.
|
||||||
|
return ((buffer.length - 1) - (writePosition - markPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes available for reading.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private int available(){
|
||||||
|
if (readPosition <= writePosition){
|
||||||
|
// any space between the first read and
|
||||||
|
// the first write is available. In this case i
|
||||||
|
// is all in one piece.
|
||||||
|
return (writePosition - readPosition);
|
||||||
|
}
|
||||||
|
// space at the beginning and end.
|
||||||
|
return (buffer.length - (readPosition - writePosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes saved for supporting marks.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private int marked(){
|
||||||
|
if (markPosition <= readPosition){
|
||||||
|
// any space between the markPosition and
|
||||||
|
// the first write is marked. In this case i
|
||||||
|
// is all in one piece.
|
||||||
|
return (readPosition - markPosition);
|
||||||
|
}
|
||||||
|
// space at the beginning and end.
|
||||||
|
return (buffer.length - (markPosition - readPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we have passed the markSize reset the
|
||||||
|
* mark so that the space can be used.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
private void ensureMark(){
|
||||||
|
if (marked() > markSize){
|
||||||
|
markPosition = readPosition;
|
||||||
|
markSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer with a default capacity.
|
||||||
|
* Writing to a full buffer will block until space
|
||||||
|
* is available rather than throw an exception.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public CircularByteBuffer(){
|
||||||
|
this (DEFAULT_SIZE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer with given capacity.
|
||||||
|
* Writing to a full buffer will block until space
|
||||||
|
* is available rather than throw an exception.
|
||||||
|
* <p>
|
||||||
|
* Note that the buffer may reserve some bytes for
|
||||||
|
* special purposes and capacity number of bytes may
|
||||||
|
* not be able to be written to the buffer.
|
||||||
|
* <p>
|
||||||
|
* Note that if the buffer is of INFINITE_SIZE it will
|
||||||
|
* neither block or throw exceptions, but rather grow
|
||||||
|
* without bound.
|
||||||
|
*
|
||||||
|
* @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public CircularByteBuffer(int size){
|
||||||
|
this (size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer with a default capacity and
|
||||||
|
* given blocking behavior.
|
||||||
|
*
|
||||||
|
* @param blockingWrite true writing to a full buffer should block
|
||||||
|
* until space is available, false if an exception should
|
||||||
|
* be thrown instead.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public CircularByteBuffer(boolean blockingWrite){
|
||||||
|
this (DEFAULT_SIZE, blockingWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer with the given capacity and
|
||||||
|
* blocking behavior.
|
||||||
|
* <p>
|
||||||
|
* Note that the buffer may reserve some bytes for
|
||||||
|
* special purposes and capacity number of bytes may
|
||||||
|
* not be able to be written to the buffer.
|
||||||
|
* <p>
|
||||||
|
* Note that if the buffer is of INFINITE_SIZE it will
|
||||||
|
* neither block or throw exceptions, but rather grow
|
||||||
|
* without bound.
|
||||||
|
*
|
||||||
|
* @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE.
|
||||||
|
* @param blockingWrite true writing to a full buffer should block
|
||||||
|
* until space is available, false if an exception should
|
||||||
|
* be thrown instead.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
public CircularByteBuffer(int size, boolean blockingWrite){
|
||||||
|
if (size == INFINITE_SIZE){
|
||||||
|
buffer = new byte[DEFAULT_SIZE];
|
||||||
|
infinite = true;
|
||||||
|
} else {
|
||||||
|
buffer = new byte[size];
|
||||||
|
infinite = false;
|
||||||
|
}
|
||||||
|
this.blockingWrite = blockingWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for reading from a circular byte buffer.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected class CircularByteBufferInputStream extends InputStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that can be read (or skipped over) from this
|
||||||
|
* input stream without blocking by the next caller of a method for this input
|
||||||
|
* stream. The next caller might be the same thread or or another thread.
|
||||||
|
*
|
||||||
|
* @return the number of bytes that can be read from this input stream without blocking.
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public int available() throws IOException {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (inputStreamClosed) throw new IOException("InputStream has been closed, it is not ready.");
|
||||||
|
return (CircularByteBuffer.this.available());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the stream. Once a stream has been closed, further read(), available(),
|
||||||
|
* mark(), or reset() invocations will throw an IOException. Closing a
|
||||||
|
* previously-closed stream, however, has no effect.
|
||||||
|
*
|
||||||
|
* @throws IOException never.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void close() throws IOException {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
inputStreamClosed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the present position in the stream. Subsequent calls to reset() will
|
||||||
|
* attempt to reposition the stream to this point.
|
||||||
|
* <p>
|
||||||
|
* The readAheadLimit must be less than the size of circular buffer, otherwise
|
||||||
|
* this method has no effect.
|
||||||
|
*
|
||||||
|
* @param readAheadLimit Limit on the number of bytes that may be read while
|
||||||
|
* still preserving the mark. After reading this many bytes, attempting to
|
||||||
|
* reset the stream will fail.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void mark(int readAheadLimit) {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
//if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot mark a closed InputStream.");
|
||||||
|
if (buffer.length - 1 > readAheadLimit) {
|
||||||
|
markSize = readAheadLimit;
|
||||||
|
markPosition = readPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell whether this stream supports the mark() operation.
|
||||||
|
*
|
||||||
|
* @return true, mark is supported.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public boolean markSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a single byte.
|
||||||
|
* This method will block until a byte is available, an I/O error occurs,
|
||||||
|
* or the end of the stream is reached.
|
||||||
|
*
|
||||||
|
* @return The byte read, as an integer in the range 0 to 255 (0x00-0xff),
|
||||||
|
* or -1 if the end of the stream has been reached
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public int read() throws IOException {
|
||||||
|
while (true){
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
|
||||||
|
int available = CircularByteBuffer.this.available();
|
||||||
|
if (available > 0){
|
||||||
|
int result = buffer[readPosition] & 0xff;
|
||||||
|
readPosition++;
|
||||||
|
if (readPosition == buffer.length){
|
||||||
|
readPosition = 0;
|
||||||
|
}
|
||||||
|
ensureMark();
|
||||||
|
return result;
|
||||||
|
} else if (outputStreamClosed){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(Exception x){
|
||||||
|
throw new IOException("Blocking read operation interrupted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bytes into an array.
|
||||||
|
* This method will block until some input is available,
|
||||||
|
* an I/O error occurs, or the end of the stream is reached.
|
||||||
|
*
|
||||||
|
* @param cbuf Destination buffer.
|
||||||
|
* @return The number of bytes read, or -1 if the end of
|
||||||
|
* the stream has been reached
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public int read(byte[] cbuf) throws IOException {
|
||||||
|
return read(cbuf, 0, cbuf.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bytes into a portion of an array.
|
||||||
|
* This method will block until some input is available,
|
||||||
|
* an I/O error occurs, or the end of the stream is reached.
|
||||||
|
*
|
||||||
|
* @param cbuf Destination buffer.
|
||||||
|
* @param off Offset at which to start storing bytes.
|
||||||
|
* @param len Maximum number of bytes to read.
|
||||||
|
* @return The number of bytes read, or -1 if the end of
|
||||||
|
* the stream has been reached
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public int read(byte[] cbuf, int off, int len) throws IOException {
|
||||||
|
while (true){
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
|
||||||
|
int available = CircularByteBuffer.this.available();
|
||||||
|
if (available > 0){
|
||||||
|
int length = Math.min(len, available);
|
||||||
|
int firstLen = Math.min(length, buffer.length - readPosition);
|
||||||
|
int secondLen = length - firstLen;
|
||||||
|
System.arraycopy(buffer, readPosition, cbuf, off, firstLen);
|
||||||
|
if (secondLen > 0){
|
||||||
|
System.arraycopy(buffer, 0, cbuf, off+firstLen, secondLen);
|
||||||
|
readPosition = secondLen;
|
||||||
|
} else {
|
||||||
|
readPosition += length;
|
||||||
|
}
|
||||||
|
if (readPosition == buffer.length) {
|
||||||
|
readPosition = 0;
|
||||||
|
}
|
||||||
|
ensureMark();
|
||||||
|
return length;
|
||||||
|
} else if (outputStreamClosed){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(Exception x){
|
||||||
|
throw new IOException("Blocking read operation interrupted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the stream.
|
||||||
|
* If the stream has been marked, then attempt to reposition i
|
||||||
|
* at the mark. If the stream has not been marked, or more bytes
|
||||||
|
* than the readAheadLimit have been read, this method has no effect.
|
||||||
|
*
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void reset() throws IOException {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot reset a closed InputStream.");
|
||||||
|
readPosition = markPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip bytes.
|
||||||
|
* This method will block until some bytes are available,
|
||||||
|
* an I/O error occurs, or the end of the stream is reached.
|
||||||
|
*
|
||||||
|
* @param n The number of bytes to skip
|
||||||
|
* @return The number of bytes actually skipped
|
||||||
|
* @throws IllegalArgumentException if n is negative.
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public long skip(long n) throws IOException, IllegalArgumentException {
|
||||||
|
while (true){
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot skip bytes on a closed InputStream.");
|
||||||
|
int available = CircularByteBuffer.this.available();
|
||||||
|
if (available > 0){
|
||||||
|
int length = Math.min((int)n, available);
|
||||||
|
int firstLen = Math.min(length, buffer.length - readPosition);
|
||||||
|
int secondLen = length - firstLen;
|
||||||
|
if (secondLen > 0){
|
||||||
|
readPosition = secondLen;
|
||||||
|
} else {
|
||||||
|
readPosition += length;
|
||||||
|
}
|
||||||
|
if (readPosition == buffer.length) {
|
||||||
|
readPosition = 0;
|
||||||
|
}
|
||||||
|
ensureMark();
|
||||||
|
return length;
|
||||||
|
} else if (outputStreamClosed){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(Exception x){
|
||||||
|
throw new IOException("Blocking read operation interrupted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for writing to a circular byte buffer.
|
||||||
|
* If the buffer is full, the writes will either block
|
||||||
|
* until there is some space available or throw an IOException
|
||||||
|
* based on the CircularByteBuffer's preference.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
protected class CircularByteBufferOutputStream extends OutputStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the stream, flushing it first.
|
||||||
|
* This will cause the InputStream associated with this circular buffer
|
||||||
|
* to read its last bytes once it empties the buffer.
|
||||||
|
* Once a stream has been closed, further write() or flush() invocations
|
||||||
|
* will cause an IOException to be thrown. Closing a previously-closed stream,
|
||||||
|
* however, has no effect.
|
||||||
|
*
|
||||||
|
* @throws IOException never.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void close() throws IOException {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (!outputStreamClosed){
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
outputStreamClosed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the stream.
|
||||||
|
*
|
||||||
|
* @throws IOException if the stream is closed.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void flush() throws IOException {
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot flush a closed OutputStream.");
|
||||||
|
if (inputStreamClosed) throw new IOException("Buffer closed by inputStream; cannot flush.");
|
||||||
|
}
|
||||||
|
// this method needs to do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an array of bytes.
|
||||||
|
* If the buffer allows blocking writes, this method will block until
|
||||||
|
* all the data has been written rather than throw an IOException.
|
||||||
|
*
|
||||||
|
* @param cbuf Array of bytes to be written
|
||||||
|
* @throws BufferOverflowException if buffer does not allow blocking writes
|
||||||
|
* and the buffer is full. If the exception is thrown, no data
|
||||||
|
* will have been written since the buffer was set to be non-blocking.
|
||||||
|
* @throws IOException if the stream is closed, or the write is interrupted.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void write(byte[] cbuf) throws IOException {
|
||||||
|
write(cbuf, 0, cbuf.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a portion of an array of bytes.
|
||||||
|
* If the buffer allows blocking writes, this method will block until
|
||||||
|
* all the data has been written rather than throw an IOException.
|
||||||
|
*
|
||||||
|
* @param cbuf Array of bytes
|
||||||
|
* @param off Offset from which to start writing bytes
|
||||||
|
* @param len - Number of bytes to write
|
||||||
|
* @throws BufferOverflowException if buffer does not allow blocking writes
|
||||||
|
* and the buffer is full. If the exception is thrown, no data
|
||||||
|
* will have been written since the buffer was set to be non-blocking.
|
||||||
|
* @throws IOException if the stream is closed, or the write is interrupted.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void write(byte[] cbuf, int off, int len) throws IOException {
|
||||||
|
while (len > 0){
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
|
||||||
|
if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");
|
||||||
|
int spaceLeft = spaceLeft();
|
||||||
|
while (infinite && spaceLeft < len){
|
||||||
|
resize();
|
||||||
|
spaceLeft = spaceLeft();
|
||||||
|
}
|
||||||
|
if (!blockingWrite && spaceLeft < len) throw new IOException("CircularByteBuffer is full; cannot write " + len + " bytes");
|
||||||
|
int realLen = Math.min(len, spaceLeft);
|
||||||
|
int firstLen = Math.min(realLen, buffer.length - writePosition);
|
||||||
|
int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1);
|
||||||
|
int written = firstLen + secondLen;
|
||||||
|
if (firstLen > 0){
|
||||||
|
System.arraycopy(cbuf, off, buffer, writePosition, firstLen);
|
||||||
|
}
|
||||||
|
if (secondLen > 0){
|
||||||
|
System.arraycopy(cbuf, off+firstLen, buffer, 0, secondLen);
|
||||||
|
writePosition = secondLen;
|
||||||
|
} else {
|
||||||
|
writePosition += written;
|
||||||
|
}
|
||||||
|
if (writePosition == buffer.length) {
|
||||||
|
writePosition = 0;
|
||||||
|
}
|
||||||
|
off += written;
|
||||||
|
len -= written;
|
||||||
|
}
|
||||||
|
if (len > 0){
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(Exception x){
|
||||||
|
throw new IOException("Waiting for available space in buffer interrupted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a single byte.
|
||||||
|
* The byte to be written is contained in the 8 low-order bits of the
|
||||||
|
* given integer value; the 24 high-order bits are ignored.
|
||||||
|
* If the buffer allows blocking writes, this method will block until
|
||||||
|
* all the data has been written rather than throw an IOException.
|
||||||
|
*
|
||||||
|
* @param c number of bytes to be written
|
||||||
|
* @throws BufferOverflowException if buffer does not allow blocking writes
|
||||||
|
* and the buffer is full.
|
||||||
|
* @throws IOException if the stream is closed, or the write is interrupted.
|
||||||
|
*
|
||||||
|
* @since ostermillerutils 1.00.00
|
||||||
|
*/
|
||||||
|
@Override public void write(int c) throws IOException {
|
||||||
|
boolean written = false;
|
||||||
|
while (!written){
|
||||||
|
synchronized (CircularByteBuffer.this){
|
||||||
|
if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
|
||||||
|
if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");
|
||||||
|
int spaceLeft = spaceLeft();
|
||||||
|
while (infinite && spaceLeft < 1){
|
||||||
|
resize();
|
||||||
|
spaceLeft = spaceLeft();
|
||||||
|
}
|
||||||
|
if (!blockingWrite && spaceLeft < 1) throw new IOException("CircularByteBuffer is full; cannot write 1 byte");
|
||||||
|
if (spaceLeft > 0){
|
||||||
|
buffer[writePosition] = (byte)(c & 0xff);
|
||||||
|
writePosition++;
|
||||||
|
if (writePosition == buffer.length) {
|
||||||
|
writePosition = 0;
|
||||||
|
}
|
||||||
|
written = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!written){
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(Exception x){
|
||||||
|
throw new IOException("Waiting for available space in buffer interrupted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
java/core/src/core/util/Collectionz.java
Normal file
98
java/core/src/core/util/Collectionz.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Collectionz
|
||||||
|
{
|
||||||
|
public static <T> List<T> toMutableList(T[] a)
|
||||||
|
{
|
||||||
|
ArrayList<T> l = new ArrayList<T>();
|
||||||
|
for (T t : a)
|
||||||
|
l.add(t);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Collection<T> filterNull (Collection<T> items)
|
||||||
|
{
|
||||||
|
List<T> l = new ArrayList<T>();
|
||||||
|
|
||||||
|
for (T i : items)
|
||||||
|
if (i != null)
|
||||||
|
l.add(i);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Collection<T> filterNull (T... items)
|
||||||
|
{
|
||||||
|
List<T> l = new ArrayList<T>();
|
||||||
|
|
||||||
|
for (T i : items)
|
||||||
|
if (i != null)
|
||||||
|
l.add(i);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void removeByFirst (Collection<? extends Pair> items, Object remove)
|
||||||
|
{
|
||||||
|
Object found = null;
|
||||||
|
for (Pair x : items)
|
||||||
|
{
|
||||||
|
if (x.first.equals(remove))
|
||||||
|
{
|
||||||
|
found = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != null)
|
||||||
|
items.remove(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void removeBySecond (Collection<? extends Pair> items, Object remove)
|
||||||
|
{
|
||||||
|
Object found = null;
|
||||||
|
for (Pair x : items)
|
||||||
|
{
|
||||||
|
if (x.second.equals(remove))
|
||||||
|
{
|
||||||
|
found = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != null)
|
||||||
|
items.remove(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public boolean containsByFirst (Collection<? extends Pair> items, Object remove)
|
||||||
|
{
|
||||||
|
for (Pair x : items)
|
||||||
|
{
|
||||||
|
if (x.first.equals(remove))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public boolean containsBySecond (Collection<? extends Pair> items, Object remove)
|
||||||
|
{
|
||||||
|
for (Pair x : items)
|
||||||
|
{
|
||||||
|
if (x.second.equals(remove))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
96
java/core/src/core/util/Comparators.java
Normal file
96
java/core/src/core/util/Comparators.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class Comparators
|
||||||
|
{
|
||||||
|
public static class SortBySecond<S> implements Comparator<Pair<?,S>>
|
||||||
|
{
|
||||||
|
Comparator<S> c;
|
||||||
|
|
||||||
|
public SortBySecond(Comparator<S> c)
|
||||||
|
{
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<?,S> p1, Pair<?,S> p2)
|
||||||
|
{
|
||||||
|
return c.compare(p1.second, p2.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortByFirst<S> implements Comparator<Pair<S,?>>
|
||||||
|
{
|
||||||
|
Comparator<S> c;
|
||||||
|
|
||||||
|
public SortByFirst(Comparator<S> c)
|
||||||
|
{
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<S,?> p1, Pair<S,?> p2)
|
||||||
|
{
|
||||||
|
return c.compare(p1.first, p2.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortByFirstReverse<S> implements Comparator<Pair<S,?>>
|
||||||
|
{
|
||||||
|
Comparator<S> c;
|
||||||
|
|
||||||
|
public SortByFirstReverse(Comparator<S> c)
|
||||||
|
{
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<S,?> p1, Pair<S,?> p2)
|
||||||
|
{
|
||||||
|
return c.compare(p2.first, p1.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortBySecondNatural<S extends Comparable<S>> implements Comparator<Pair<?,S>>
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<?, S> o1, Pair<?, S> o2)
|
||||||
|
{
|
||||||
|
return o1.second.compareTo(o2.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortByFirstNatural<S extends Comparable<S>> implements Comparator<Pair<S,?>>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<S,?> o1, Pair<S,?> o2)
|
||||||
|
{
|
||||||
|
return o1.first.compareTo(o2.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortBySecondNaturalOpposite<S extends Comparable<S>> implements Comparator<Pair<?,S>>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<?, S> o1, Pair<?, S> o2)
|
||||||
|
{
|
||||||
|
return o2.second.compareTo(o1.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SortByFirstNaturalOpposite<S extends Comparable<S>> implements Comparator<Pair<S,?>>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<S,?> o1, Pair<S,?> o2)
|
||||||
|
{
|
||||||
|
return o2.first.compareTo(o1.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
java/core/src/core/util/DateFormat.java
Normal file
38
java/core/src/core/util/DateFormat.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class DateFormat
|
||||||
|
{
|
||||||
|
SimpleDateFormat sdf;
|
||||||
|
|
||||||
|
public DateFormat(String format)
|
||||||
|
{
|
||||||
|
sdf = new SimpleDateFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format(Date date, int i)
|
||||||
|
{
|
||||||
|
sdf.setTimeZone(TimeZone.getTimeZone("GMT-"+i+":00"));
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format(Date date)
|
||||||
|
{
|
||||||
|
return format(date, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date parse(String time) throws ParseException
|
||||||
|
{
|
||||||
|
return sdf.parse(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
111
java/core/src/core/util/Environment.java
Normal file
111
java/core/src/core/util/Environment.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import core.connector.FileInfo;
|
||||||
|
//import core.connector.sync.StoreConnector;
|
||||||
|
|
||||||
|
|
||||||
|
public class Environment extends HashMap<String,String>
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public Environment ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public static Environment fromStore (StoreConnector connector) throws Exception
|
||||||
|
{
|
||||||
|
Environment e = new Environment ();
|
||||||
|
connector.open();
|
||||||
|
e.readFromStore(connector);
|
||||||
|
connector.close();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readFromStore (StoreConnector connector) throws Exception
|
||||||
|
{
|
||||||
|
List<FileInfo> files = connector.listDirectory("");
|
||||||
|
for (FileInfo file : files)
|
||||||
|
{
|
||||||
|
put(file.relativePath, new String(connector.get(file.relativePath), "UTF-8"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void toStore (StoreConnector connector, Environment e) throws Exception
|
||||||
|
{
|
||||||
|
connector.open();
|
||||||
|
e.writeToStore(connector);
|
||||||
|
connector.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeToStore (StoreConnector connector) throws Exception
|
||||||
|
{
|
||||||
|
for (String key : keySet())
|
||||||
|
connector.put(key, Strings.toBytes(this.get(key)));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public String checkGet (String key)
|
||||||
|
{
|
||||||
|
// find a better exception
|
||||||
|
if (!containsKey(key))
|
||||||
|
throw new NullPointerException("Unknown key: " + key);
|
||||||
|
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment childEnvironment (String key)
|
||||||
|
{
|
||||||
|
Environment e = new Environment();
|
||||||
|
String prefix = key + "/";
|
||||||
|
int prefixLength = prefix.length();
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> i : entrySet())
|
||||||
|
{
|
||||||
|
String k = i.getKey();
|
||||||
|
if (k.startsWith(prefix))
|
||||||
|
{
|
||||||
|
e.put(k.substring(prefixLength), i.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChildEnvironment (String key, Environment e)
|
||||||
|
{
|
||||||
|
String prefix = key + "/";
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> i : e.entrySet())
|
||||||
|
{
|
||||||
|
String k = i.getKey();
|
||||||
|
this.put(prefix + k, i.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasChildEnvironment (String key)
|
||||||
|
{
|
||||||
|
String prefix = key + "/";
|
||||||
|
int prefixLength = prefix.length();
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> i : entrySet())
|
||||||
|
{
|
||||||
|
String k = i.getKey();
|
||||||
|
if (k.startsWith(prefix))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
11
java/core/src/core/util/ExceptionHandler.java
Normal file
11
java/core/src/core/util/ExceptionHandler.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
public interface ExceptionHandler
|
||||||
|
{
|
||||||
|
public void exception (Object ... arguments);
|
||||||
|
}
|
39
java/core/src/core/util/ExternalResource.java
Normal file
39
java/core/src/core/util/ExternalResource.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Author: Timothy Prepscius
|
||||||
|
* License: GPLv3 Affero + keep my name in the code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core.util;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class ExternalResource
|
||||||
|
{
|
||||||
|
static LogOut log = new LogOut(ExternalResource.class);
|
||||||
|
|
||||||
|
static protected String prefix;
|
||||||
|
|
||||||
|
static {
|
||||||
|
prefix = System.getProperty("user.home") + "/resources/";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] get(String key) throws Exception
|
||||||
|
{
|
||||||
|
String path = prefix + key;
|
||||||
|
log.debug("get", path);
|
||||||
|
return Streams.readFullyBytes(new FileInputStream(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getResourceAsStream(Class<?> c, String key) throws Exception
|
||||||
|
{
|
||||||
|
String path = prefix + c.getPackage().getName() + "/" + key;
|
||||||
|
log.debug("getResourceAsStream", path);
|
||||||
|
return new FileInputStream(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTrimmedString(String key) throws Exception
|
||||||
|
{
|
||||||
|
return Strings.toString(get(key)).trim();
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user