WalletApiImpl.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.wallet;
import static hera.util.ValidationUtils.assertNotNull;
import hera.api.model.AccountAddress;
import hera.api.model.Authentication;
import hera.api.model.RawTransaction;
import hera.api.model.Transaction;
import hera.api.model.internal.TryCountAndInterval;
import hera.client.AergoClient;
import hera.exception.InvalidAuthenticationException;
import hera.exception.WalletException;
import hera.exception.WalletExceptionConverter;
import hera.key.Signer;
import hera.keystore.KeyStore;
import hera.util.ExceptionConverter;
import hera.util.Sha256Utils;
import hera.wallet.internal.ClientInjectable;
import hera.wallet.internal.QueryApiImpl;
import hera.wallet.internal.TransactionApiImpl;
import lombok.Getter;
public class WalletApiImpl implements WalletApi {
protected final ExceptionConverter<WalletException> converter = new WalletExceptionConverter();
protected final KeyStore keyStore;
protected final TransactionApi transactionApi;
protected final QueryApi queryApi = new QueryApiImpl();
protected AergoClient aergoClient = null;
protected Signer signer = null;
protected String authMac = null;
@Getter
protected AccountAddress principal = null;
WalletApiImpl(final KeyStore keyStore, final TryCountAndInterval tryCountAndInterval) {
assertNotNull(keyStore);
assertNotNull(tryCountAndInterval);
this.keyStore = keyStore;
this.transactionApi = new TransactionApiImpl(tryCountAndInterval, this);
}
@Override
public void bind(final AergoClient aergoClient) {
assertNotNull(aergoClient);
this.aergoClient = aergoClient;
if (transactionApi instanceof ClientInjectable) {
((ClientInjectable) transactionApi).setClient(aergoClient);
}
if (queryApi instanceof ClientInjectable) {
((ClientInjectable) queryApi).setClient(aergoClient);
}
}
@Override
public synchronized boolean unlock(final Authentication authentication) {
try {
assertNotNull(authentication, "Authentication must not null");
this.signer = keyStore.load(authentication);
this.authMac = digest(authentication);
this.principal = signer.getPrincipal();
return true;
} catch (InvalidAuthenticationException e) {
return false;
} catch (Exception e) {
throw converter.convert(e);
}
}
@Override
public synchronized boolean lock(final Authentication authentication) {
try {
assertNotNull(authentication, "Authentication must not null");
final String digested = digest(authentication);
if (null == this.authMac || false == this.authMac.equals(digested)) {
return false;
}
this.signer = null;
this.authMac = null;
return true;
} catch (Exception e) {
throw converter.convert(e);
}
}
protected String digest(final Authentication authentication) {
final byte[] rawIdentity = authentication.getIdentity().getValue().getBytes();
final byte[] rawPassword = authentication.getPassword().getBytes();
final byte[] plaintext = new byte[rawIdentity.length + rawPassword.length];
System.arraycopy(rawIdentity, 0, plaintext, 0, rawIdentity.length);
System.arraycopy(rawPassword, 0, plaintext, rawIdentity.length, rawPassword.length);
return new String(Sha256Utils.digest(plaintext));
}
@Override
public TransactionApi transactionApi() {
if (null == this.aergoClient) {
throw new WalletException("Bind client first by 'WalletApi.bind(aergoClient)'");
}
return this.transactionApi;
}
@Override
public QueryApi queryApi() {
if (null == this.aergoClient) {
throw new WalletException("Bind client first by 'WalletApi.bind(aergoClient)'");
}
return this.queryApi;
}
@Override
public Transaction sign(final RawTransaction rawTransaction) {
try {
assertNotNull(rawTransaction, "Raw transaction must not null");
if (!getPrincipal().equals(rawTransaction.getSender())) {
throw new WalletException("Sender of the rawTransaction should equals with unlocked one");
}
return getSigner().sign(rawTransaction);
} catch (Exception e) {
throw converter.convert(e);
}
}
@Override
public String toString() {
final AccountAddress current = getPrincipal();
return String.format("WalletApi(keyStore=%s, pricipal=%s)", keyStore.getClass().getName(),
null == current ? null : current.getEncoded());
}
protected Signer getSigner() {
if (null == this.signer) {
throw new WalletException("Unlock account first");
}
return this.signer;
}
}