[dak/master] Add replay protection for uploaded changes files.
Look in signature_history table if the changes was already seen to
prevent re-uploading old changes files.
---
daklib/checks.py | 13 +++++++++++++
daklib/dbconn.py | 3 +++
daklib/upload.py | 8 ++++++++
3 files changed, 24 insertions(+)
diff --git a/daklib/checks.py b/daklib/checks.py
index dce112b..b7931f2 100644
--- a/daklib/checks.py
+++ b/daklib/checks.py
@@ -109,6 +109,18 @@ class Check(object):
return False
class SignatureAndHashesCheck(Check):
+ def check_replay(self, upload):
+ # Use private session as we want to remember having seen the .changes
+ # in all cases.
+ session = DBConn().session()
+ history = SignatureHistory.from_signed_file(upload.changes)
+ r = history.query(session)
+ if r is not None:
+ raise Reject('Signature for changes file was already seen at {0}'.format(r.seen))
+ session.add(history)
+ session.commit()
+ return True
+
"""Check signature of changes and dsc file (if included in upload)
Make sure the signature is valid and done by a known user.
@@ -117,6 +129,7 @@ class SignatureAndHashesCheck(Check):
changes = upload.changes
if not changes.valid_signature:
raise Reject("Signature for .changes not valid.")
+ self.check_replay(upload)
self._check_hashes(upload, changes.filename, changes.files.itervalues())
source = None
diff --git a/daklib/dbconn.py b/daklib/dbconn.py
index e55c283..c2621e3 100644
--- a/daklib/dbconn.py
+++ b/daklib/dbconn.py
@@ -1859,6 +1859,9 @@ class SignatureHistory(ORMObject):
self.contents_sha1 = signed_file.contents_sha1()
return self
+ def query(self, session):
+ return session.query(SignatureHistory).filter_by(fingerprint=self.fingerprint, signature_timestamp=self.signature_timestamp, contents_sha1=self.contents_sha1).first()
+
__all__.append('SignatureHistory')
################################################################################
diff --git a/daklib/upload.py b/daklib/upload.py
index 406b1d4..ec120a7 100644
--- a/daklib/upload.py
+++ b/daklib/upload.py
@@ -275,6 +275,14 @@ class Changes(object):
return self._signed_file.valid
@property
+ def signature_timestamp(self):
+ return self._signed_file.signature_timestamp
+
+ @property
+ def contents_sha1(self):
+ return self._signed_file.contents_sha1
+
+ @property
def architectures(self):
"""list of architectures included in the upload
@type: list of str
--
1.7.10.4
Reply to: