New port numbers
[electrum-nvc.git] / lib / paymentrequest.py
index 37572ef..91cd0ac 100644 (file)
@@ -49,22 +49,14 @@ import x509
 REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'}
 ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'}
 
-# status can be:
-PR_UNPAID  = 0
-PR_EXPIRED = 1
-PR_SENT    = 2     # sent but not propagated
-PR_PAID    = 3     # send and propagated
-PR_ERROR   = 4     # could not parse
-
 
 ca_list = {}
-ca_path = os.path.expanduser("~/.electrum/ca/ca-bundle.crt")
+ca_path = requests.certs.where()
 
 
 
 
 def load_certificates():
-
     try:
         ca_f = open(ca_path, 'r')
     except Exception:
@@ -84,7 +76,7 @@ def load_certificates():
             try:
                 x.parse(c)
             except Exception as e:
-                print "cannot parse cert:", e
+                util.print_error("cannot parse cert:", e)
             ca_list[x.getFingerprint()] = x
     ca_f.close()
     util.print_error("%d certificates"%len(ca_list))
@@ -141,6 +133,8 @@ class PaymentRequest:
         with open(filename,'r') as f:
             r = f.read()
 
+        assert key == bitcoin.sha256(r)[0:16].encode('hex')
+        self.id = key
         self.parse(r)
 
 
@@ -175,8 +169,11 @@ class PaymentRequest:
             x.slow_parse()
             x509_chain.append(x)
             if i == 0:
-                if not x.check_name(self.domain):
-                    self.error = "Certificate Domain Mismatch"
+                try:
+                    x.check_date()
+                    x.check_name(self.domain)
+                except Exception as e:
+                    self.error = str(e)
                     return
             else:
                 if not x.check_ca():
@@ -192,13 +189,19 @@ class PaymentRequest:
             prev_x = x509_chain[i-1]
 
             algo, sig, data = prev_x.extract_sig()
-            if algo.getComponentByName('algorithm') != x509.ALGO_RSA_SHA1:
-                self.error = "Algorithm not suported"
-                return
-
             sig = bytearray(sig[5:])
             pubkey = x.publicKey
-            verify = pubkey.hashAndVerify(sig, data)
+            if algo.getComponentByName('algorithm') == x509.ALGO_RSA_SHA1:
+                verify = pubkey.hashAndVerify(sig, data)
+            elif algo.getComponentByName('algorithm') == x509.ALGO_RSA_SHA256:
+                hashBytes = bytearray(hashlib.sha256(data).digest())
+                prefixBytes = bytearray([0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20])
+                verify = pubkey.verify(sig, prefixBytes + hashBytes)
+            else:
+                self.error = "Algorithm not supported" 
+                util.print_error(self.error, algo.getComponentByName('algorithm'))
+                return
+
             if not verify:
                 self.error = "Certificate not Signed by Provided CA Certificate Chain"
                 return
@@ -246,7 +249,7 @@ class PaymentRequest:
 
         for o in pay_det.outputs:
             addr = transaction.get_address_from_output_script(o.script)[1]
-            self.outputs.append( (addr, o.amount) )
+            self.outputs.append( ('address', addr, o.amount) )
 
         self.memo = self.details.memo
 
@@ -257,17 +260,16 @@ class PaymentRequest:
 
         self.payment_url = self.details.payment_url
 
-        #if self.has_expired():
-        #    self.error = "ERROR: Payment Request has Expired."
-        #    return False
-
         return True
 
     def has_expired(self):
         return self.details.expires and self.details.expires < int(time.time())
 
+    def get_expiration_date(self):
+        return self.details.expires
+
     def get_amount(self):
-        return sum(map(lambda x:x[1], self.outputs))
+        return sum(map(lambda x:x[2], self.outputs))
 
     def get_domain(self):
         return self.domain
@@ -283,9 +285,6 @@ class PaymentRequest:
 
     def send_ack(self, raw_tx, refund_addr):
 
-        if self.has_expired():
-            return False, "has expired"
-
         pay_det = self.details
         if not self.details.payment_url:
             return False, "no url"
@@ -295,7 +294,7 @@ class PaymentRequest:
         paymnt.transactions.append(raw_tx)
 
         ref_out = paymnt.refund_to.add()
-        ref_out.script = transaction.Transaction.pay_script(refund_addr)
+        ref_out.script = transaction.Transaction.pay_script('address', refund_addr)
         paymnt.memo = "Paid using Electrum"
         pm = paymnt.SerializeToString()
 
@@ -330,12 +329,17 @@ if __name__ == "__main__":
         uri = sys.argv[1]
     except:
         print "usage: %s url"%sys.argv[0]
-        print "example url: \"bitcoin:mpu3yTLdqA1BgGtFUwkVJmhnU3q5afaFkf?r=https%3A%2F%2Fbitcoincore.org%2F%7Egavin%2Ff.php%3Fh%3D2a828c05b8b80dc440c80a5d58890298&amount=1\""
+        print "example url: \"novacoin:4LJgtjeXMjLA6nVzYMJh1LEkwxMFsRtnP4?amount=0.0018&r=https%3A%2F%2Fsite.com%2F\""
         sys.exit(1)
 
-    address, amount, label, message, request_url, url = util.parse_url(uri)
-    pr = PaymentRequest(request_url)
+    address, amount, label, message, request_url = util.parse_URI(uri)
+    from simple_config import SimpleConfig
+    config = SimpleConfig()
+    pr = PaymentRequest(config)
+    pr.read(request_url)
     if not pr.verify():
+        print 'verify failed'
+        print pr.error
         sys.exit(1)
 
     print 'Payment Request Verified Domain: ', pr.domain