[Webfunds-commits] java/webfunds/sox Receipt.java
Ian Grigg
iang@cypherpunks.ai
Fri, 6 Apr 2001 19:52:41 -0400 (AST)
iang 01/04/06 19:52:41
Modified: webfunds/sox Receipt.java
Log:
additional support for AbstractPayments and Float accounts
Revision Changes Path
1.44 +214 -59 java/webfunds/sox/Receipt.java
Index: Receipt.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/Receipt.java,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -r1.43 -r1.44
--- Receipt.java 2001/03/23 15:06:03 1.43
+++ Receipt.java 2001/04/06 23:52:40 1.44
@@ -1,15 +1,27 @@
/*
- * $Id: Receipt.java,v 1.43 2001/03/23 15:06:03 iang Exp $
+ * $Id: Receipt.java,v 1.44 2001/04/06 23:52:40 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.sox;
-import java.io.*;
-import java.security.*;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.KeyException;
+
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import webfunds.utils.Panic;
+
/**
* This class represents a signed receipt,
* such as received from an issuer in response
@@ -39,14 +51,15 @@
public int getVersion() { return version; }
- /**
- * SOX format for these hashes is the PGP format with leading byte.
- */
- protected static final int MD_SHA1 = 2;
protected DepositRequest depositRequest;
protected byte[] depositRequestData;
+ /**
+ * The Exchange Payment is what is returned in case of a Withdrawal.
+ * When in the receipt, it is a signed version of the Proto Payment
+ * in the DepositRequest.
+ */
protected AbstractPayment exPayment;
protected byte[] exPaymentData;
@@ -90,7 +103,25 @@
* replace it with a signed payment.
*/
public AbstractPayment getExchangePayment() { return exPayment; }
- public void setExchangePayment(AbstractPayment p) { exPayment = p; }
+ public void setExchangePayment(AbstractPayment p)
+ throws SOXPacketException
+ {
+ exPayment = p;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ p.encode(baos);
+ } catch(IOException e) {
+ e.printStackTrace();
+ throw new SOXPacketException(e.getMessage());
+ }
+ exPaymentData = baos.toByteArray();
+ }
+ public void setExchangePayment(byte[] data)
+ throws SOXPacketException
+ {
+ exPaymentData = data;
+ exPayment = PaymentFactory.decode(data);
+ }
/**
* Get the DepositRequest object that was used to deposit the payment
@@ -180,18 +211,24 @@
}
- public boolean isValid()
+ private boolean isValid()
{
int errors = 0;
- String pid = depositRequest.getPaymentId();
+// System.err.println("CHECK VALIDITY OF: " + toString() + "\n\n");
+
+ AbstractPayment pay = depositRequest.getPay();
+
+// System.err.println(" against these contents of Pay: " + pay);
+
+ String pid = pay.getId();
String did = depositRequest.getDepositId();
AccountId tgt = depositRequest.getTarget();
AccountId src = depositRequest.getSource();
ItemId item = depositRequest.getItem();
long qty = depositRequest.getQty();
- if (!pid.equals(this.pid))
+ if (pay instanceof Payment && !pid.equals(this.pid))
{
logmsg("mismatch PID: "+pid+" != "+this.pid);
errors++;
@@ -207,7 +244,7 @@
logmsg("mismatch Target: "+tgt+" != "+this.tgt);
errors++;
}
- if (!src.equals(this.src))
+ if (!src.equals(this.src) && !src.isOpen())
{
logmsg("mismatch Source: "+src+" != "+this.src);
errors++;
@@ -217,6 +254,20 @@
logmsg("mismatch Item: "+item+" != "+this.item);
errors++;
}
+ int id = item.getOpenPGPId();
+ if (id != Id.MD_SHA1)
+ {
+ logmsg("not a SHA hash: " + item + " (" + id + ")");
+ logmsg("payment is " + pay);
+ errors++;
+ }
+ byte[] b = item.getByteArray();
+ if ((b == null) || (b.length != 20))
+ {
+ logmsg("not a SHA len: " + item);
+ logmsg("payment is " + pay);
+ errors++;
+ }
if (qty != this.qty)
{
logmsg("mismatch Item: "+qty+" != "+this.qty);
@@ -228,6 +279,7 @@
{
logmsg("Receipt bad: " + errors + " errors.");
}
+// System.err.println("END CHECK VALIDITY");
return 0 == errors;
}
@@ -268,7 +320,7 @@
this.depositRequest = req;
if (!isValid())
- throw new SOXPacketException("dud Receipt");
+ throw new SOXPacketException("dud Receipt: " + this);
//
// Some receipts for this time had problems with the time.
@@ -426,47 +478,44 @@
if (version >= RECEIPT_PROTO)
flags = dis.readLong();
- //
- // Perl code shoves a one byte (OpenPGP) Message Digest Type
- // in front of hashes.
- //
- int hash_type = dis.readUnsignedByte();
- if (MD_SHA1 != hash_type)
- throw new SOXPacketException(
- "Unknown Hash type: SHA=2 != " + hash_type);
- item = new ItemId(dis);
+// System.err.println("Receipt decode started with " + vstring());
+
+ item = decodeItemId(dis);
qty = dis.readLong();
+// System.err.println("Receipt qty " + qty + " of item " + item);
timestamp = dis.readLong();
+// System.err.println("time " + timestamp);
xid = readString(dis);
pid = readString(dis);
did = readString(dis);
+// System.err.println("xid " + xid + " pid " + pid + " did " + did);
- hash_type = dis.readUnsignedByte();
- if (MD_SHA1 != hash_type)
- throw new SOXPacketException(
- "Unknown Hash type: SHA=2 != " + hash_type);
- tgt = new AccountId(dis);
- hash_type = dis.readUnsignedByte();
- if (MD_SHA1 != hash_type)
- throw new SOXPacketException(
- "Unknown Hash type: SHA=2 != " + hash_type);
- src = new AccountId(dis);
+ tgt = decodeAccountId(dis);
+// System.err.println("decoded tgt: " + tgt);
+ src = decodeAccountId(dis);
+// System.err.println("decoded src: " + src);
depositRequestData = readByteArray(dis);
+// System.err.println("deposit byte array len: " + depositRequestData.length);
depositRequest = new DepositRequest(depositRequestData);
+// System.err.println("decoded deposit: " + depositRequest);
exPaymentData = null;
exPayment = null;
- if (version >= RECEIPT_PROTO && isWithdrawalReceipt())
+ if ((version >= RECEIPT_PROTO) && isWithdrawalReceipt())
{
exPaymentData = readByteArray(dis);
- exPayment = new Payment(exPaymentData);
+// System.err.println("decoding ProtoPay " + exPaymentData.length);
+ exPayment = PaymentFactory.decode(exPaymentData);
}
+// System.err.println("reading sig");
sig = readByteArray(dis);
+// System.err.println("getting HashSig");
byte[] my_sig = getHashSig();
+// System.err.println("HashSig is " + webfunds.utils.Hex.printable(my_sig));
if (!Utils.byteEquals(my_sig, sig))
{
@@ -475,13 +524,59 @@
webfunds.utils.Hex.data2hex(sig) + " (=packet)");
}
+// System.err.println("check validity:");
if (!isValid())
{
+// System.err.println("is bad validity:");
throw new SOXPacketException("Dud Receipt");
}
+// System.err.println("is good validity, PASSED!");
}
/**
+ * Get SOX2 Hash for an ItemId, which has an
+ * OpenPGP Message Digest Type in advance of it.
+ * ItemId is only SHA.
+ */
+ protected ItemId decodeItemId(DataInputStream dis)
+ throws SOXPacketException, IOException
+ {
+ int hash_type = dis.readUnsignedByte();
+ if (
+ (Id.MD_SHA1 != hash_type)
+ )
+ throw new SOXPacketException(
+ "Unknown Hash type: SHA=2 != " + hash_type);
+
+ ItemId hash = new ItemId(dis);
+ hash.setOpenPGPId(hash_type);
+ return hash;
+ }
+
+ /**
+ * Get SOX2 Hash for an AccountId, which has an
+ * OpenPGP Message Digest Type in advance of it.
+ * This one can be NAH for token float accounts,
+ * ones that are not directly accessible from
+ * outside.
+ */
+ protected AccountId decodeAccountId(DataInputStream dis)
+ throws SOXPacketException, IOException
+ {
+ int hash_type = dis.readUnsignedByte();
+ if (
+ (Id.MD_SHA1 != hash_type) &&
+ (Id.MD_NAH != hash_type)
+ )
+ throw new SOXPacketException(
+ "Unknown Hash type: NAH=110/SHA=2 != " + hash_type);
+
+ AccountId hash = new AccountId(dis);
+ hash.setOpenPGPId(hash_type);
+ return hash;
+ }
+
+ /**
* PRETEND Signature - the receipt is signed with a SHA1 MD,
* encoded as a message digest (type, data) within a string.
* Hmm, this gives us a problem when we start using DSA,
@@ -507,7 +602,7 @@
int full_len = sig_array.length + 1;
byte[] lam_sig = new byte[full_len];
- lam_sig[0] = MD_SHA1;
+ lam_sig[0] = Id.MD_SHA1;
for (int i = 1; i < full_len; i++)
lam_sig[i] = sig_array[i-1];
return lam_sig;
@@ -540,8 +635,9 @@
if (version >= RECEIPT_PROTO)
dos.writeLong(flags);
- dos.writeByte(MD_SHA1);
- item.encode(dos);
+ // dos.writeByte(Id.MD_SHA1);
+ // item.encode(dos);
+ encodeId(item, dos);
dos.writeLong(qty);
dos.writeLong(timestamp);
@@ -549,10 +645,12 @@
writeString(dos, pid);
writeString(dos, did);
- dos.writeByte(MD_SHA1);
- tgt.encode(dos);
- dos.writeByte(MD_SHA1);
- src.encode(dos);
+ encodeId(tgt, dos);
+ encodeId(src, dos);
+ // dos.writeByte(Id.MD_SHA1);
+ // tgt.encode(dos);
+ // dos.writeByte(Id.MD_SHA1);
+ // src.encode(dos);
// written as array, as original might vary on encode()
writeByteArray(dos, depositRequestData);
@@ -561,14 +659,32 @@
}
/**
- * Encode a receipt, writing the data to an output stream,
- * in a format suitable for sending to restoring using
- * the decode() method to re-construct the object.
+ * Encode a SOX2 hash, with OpenPGP id as a byte before it.
+ * Used for hashes in the receipt body.
*
- * @param os the stream on which to send the output
- * @return byte[] the receipt in encoded form
- * @excep an I/O error occurred writing to the output stream
+ * @param dos the stream on which to send the output
+ * @return byte[] the receipt in encoded form
+ * @excep an I/O error occurred writing to the output stream
*/
+ public void encodeId(Id id, DataOutputStream dos)
+ throws IOException
+ {
+ int openPGPid = id.getOpenPGPId();
+ if (openPGPid < 0)
+ throw new IOException("unknown hash type: " + openPGPid + "; "+id);
+ dos.writeByte(openPGPid);
+ id.encode(dos);
+ }
+
+ /**
+ * Encode a receipt, writing the data to an output stream,
+ * in a format suitable for sending to restoring using
+ * the decode() method to re-construct the object.
+ *
+ * @param os the stream on which to send the output
+ * @return byte[] the receipt in encoded form
+ * @excep an I/O error occurred writing to the output stream
+ */
public void encode(OutputStream os)
throws IOException
{
@@ -647,17 +763,31 @@
*/
public String toString()
{
- String retval = "SOX Receipt:\n";
+ String s = "SOX Receipt: " + vstring() + "\n";
- retval += "\titem: "+item+"\tqty: "+qty+ "\n";
- retval += "\txid: "+xid+"\tpid: "+pid+ "\tdid: "+did+ "\n";
- retval += "\ttime: "+timestamp+"\tDesc: "+
+ s += " item: "+item+" Q="+qty+ "\n";
+ s += " xid: "+xid+" pid="+pid+ " did="+did+ "\n";
+ s += " time: "+timestamp+"\tDesc: "+
webfunds.utils.Hex.printable(getPaymentDesc())+"\n";
- retval += "\tsrc: "+src.fp()+"\ttgt: "+tgt.fp()+ "\n";
+ s += " src: "+src.fp()+"\ttgt: "+tgt.fp()+ "\n";
+ s += " DR: "+depositRequest+"\n";
+ if (isWithdrawalReceipt())
+ s += " Withdraws: "+exPayment+"\n";
if (sig != null)
- retval += "\tSignature: "+sig+"\n";
+ s += " Signature: "+sig+"\n";
+ s += "=========================== END Receipt\n";
- return retval;
+ return s;
+ }
+
+ public String vstring()
+ {
+ String s = "V" + version;
+
+ if (version >= RECEIPT_PROTO)
+ s += " f=" + flags;
+
+ return s;
}
/** @return a receipt that is only mildly internally valid */
@@ -665,8 +795,6 @@
{
DepositRequest req = DepositRequest.example();
-//System.err.println("Payment: " + req.getPayment());
-
AbstractPayment p = req.getPay();
long from = p.getValidFrom() / 1000;
from *= 1000;
@@ -676,7 +804,6 @@
if (relTime < 0) relTime = -relTime;
relTime = relTime % (till - from);
long absTime = from + relTime;
-//System.err.println(" "+from+" "+till+" "+relTime+" "+absTime);
String xid = Utils.exampleString();
@@ -687,6 +814,15 @@
ItemId item = req.getItem();
long qty = req.getQty();
+ /*
+ * A receipt cannot be written to/from an open accountId,
+ * but it can be to/from an internal Float account.
+ */
+ if (tgt.isOpen())
+ tgt = AccountId.example(Id.LEN_NAH);
+ if (src.isOpen())
+ src = AccountId.example(Id.LEN_NAH);
+
Receipt receipt;
try {
receipt = new Receipt(
@@ -699,11 +835,29 @@
throw new RuntimeException("SOXPEx: " + ex);
}
+ /*
+ * In the event of a withdrawal, the withdrawn payment
+ * needs to be added to the Receipt, hopefully signed
+ * by the Issuer. in this case, we cheat and just shove
+ * in the proto payment from the DR.
+ */
+ if (req.getTypeOfPayment() != PaymentFactory.NONE) // wrong for SOX
+ {
+ receipt.version = RECEIPT_PROTO;
+ receipt.flags = WITHDRAW_PROTO;
+ AbstractPayment proto = req.getProto();
+ try {
+ receipt.setExchangePayment(proto);
+ } catch (SOXPacketException ex) {
+ throw new Panic("Proto: " + ex);
+ }
+ }
+
try {
receipt.setSignature(receipt.getHashSig());
} catch (IOException ex) {
ex.printStackTrace();
- throw new RuntimeException("sig IOEx: " + ex);
+ throw new Panic("sig IOEx: " + ex);
}
return receipt ;
@@ -711,7 +865,7 @@
public static void main(String[] args)
{
- int num = 200;
+ int num = 20000;
String type = "-c";
if (args.length > 0)
{
@@ -767,6 +921,7 @@
protected static void cycle()
throws Exception
{
+// System.err.println("\n\n\n\n\n\n\n\n\n\n");
Receipt p = example();
System.err.println("Writing: " + p);
ByteArrayOutputStream baos = new ByteArrayOutputStream();