Page MenuHomeSoftware Heritage

D82.diff
No OneTemporary

D82.diff

diff --git a/swh/web/ui/static/js/search.js b/swh/web/ui/static/js/search.js
new file mode 100644
--- /dev/null
+++ b/swh/web/ui/static/js/search.js
@@ -0,0 +1,242 @@
+/**
+ * Search page management
+ * Args:
+ * textForm: the form containing the text input, if any
+ * fileForm: the form containing the file input, if any
+ * messageElem: the element that should display search messages
+ */
+var SearchFormController = function(textForm, fileForm, messageElem)
+
+{
+ this.textForm = textForm;
+ this.fileForm = fileForm;
+ this.messageElem = messageElem;
+
+ // List of hashes to check against files being processed
+ this.hashed_already = {
+ 'sha1': {},
+ 'sha256': {},
+ 'sha1_git': {}
+ };
+ this.algos = ['sha1', 'sha256', 'sha1_git'];
+ this.CHECKSUM_RE = /^([0-9a-f]{40}|[0-9a-f]{64})$/i;
+ var self = this;
+
+ /**
+ * Show search messages on the page
+ * Args:
+ * msg: the message to show
+ */
+ this.searchMessage = function(msg) {
+ self.messageElem.empty();
+ self.messageElem.text(msg);
+ };
+
+ /**
+ * Setup the text field
+ * Args:
+ * textFormInput: the text form's input
+ */
+ this.setupTextForm = function(textFormInput) {
+ self.textForm.submit(function(event) {
+ var q = textFormInput.val();
+ if (!q) {
+ event.preventDefault();
+ self.searchMessage("Please enter a SHA-1 or SHA-256 checksum.");
+ }
+ else if (q && !q.match(self.CHECKSUM_RE)) {
+ event.preventDefault();
+ self.searchMessage("Invalid SHA-1 or SHA-256 checksum");
+ }
+ });
+ };
+
+ /**
+ * Setup the file drag&drop UI and hashing support.
+ * Args:
+ * fileDropElem: the element receptive to drag & drop
+ * hashedListerElem: the element that receives the hased file descriptions
+ * fileFormInput: the input that actually receives files
+ * clearButton: the button used to clear currently hashed files
+ */
+ this.setupFileForm = function(fileDropElem, hashedListerElem, fileFormInput, clearButton) {
+ if (!FileReader || !CryptoJS) {
+ self.searchMessage("Client-side file hashing is not available for your browser.");
+ return;
+ }
+
+ // Enable clicking on the text element for file picker
+ fileDropElem.click(function(event) {
+ event.preventDefault();
+ fileFormInput.click();
+ });
+
+ // Enable drag&drop
+ var makeDroppable = function(fileReceptionElt) {
+ var fileshovering = false;
+
+ fileReceptionElt.on('dragover', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ });
+
+ fileReceptionElt.on('dragenter', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (!fileshovering) {
+ fileReceptionElt.css("border-style", "solid");
+ fileReceptionElt.css("box-shadow", "inset 0 3px 4px");
+ fileshovering = true;
+ }
+ });
+
+ fileReceptionElt.on('dragover', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (!fileshovering) {
+ fileReceptionElt.css("border-style", "solid");
+ fileReceptionElt.css("box-shadow", "inset 0 3px 4px");
+ fileshovering = true;
+ }
+ });
+
+ fileReceptionElt.on('dragleave', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (fileshovering) {
+ fileReceptionElt.css("border-style", "dashed");
+ fileReceptionElt.css("box-shadow", "none");
+ fileshovering = false;
+ }
+ });
+
+ fileReceptionElt.on('drop', function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (fileshovering) {
+ fileReceptionElt.css("border-style", "dashed");
+ fileReceptionElt.css("box-shadow", "none");
+ fileshovering = false;
+ }
+ var myfiles = event.originalEvent.dataTransfer.files;
+ readAndHash(myfiles);
+ });
+ };
+ makeDroppable(fileDropElem);
+
+ // Connect input change and rehash
+ var makeInputChange = function(fileInput) {
+ return fileInput.each(function() {
+ $(this).on('change', function(){
+ readAndHash(this.files);
+ });
+ });
+ };
+ makeInputChange(fileFormInput);
+
+ // Connect clear button
+ var makeClearButton = function(button) {
+ return button.each(function() {
+ $(this).click(function(event) {
+ event.preventDefault();
+ hashedListerElem.empty();
+ self.fileForm.children('.search-hidden').remove();
+ self.hashed_already = {
+ 'sha1': {},
+ 'sha256': {},
+ 'sha1_git': {}
+ };
+ });
+ });
+ };
+ makeClearButton(clearButton);
+
+ var readAndHash = function(filelist) {
+ for (var file_idx = 0; file_idx < filelist.length; file_idx++) {
+ var file = filelist.item(file_idx);
+ var fr = new FileReader();
+ bindReader(fr, file.name);
+ fr.readAsArrayBuffer(file);
+ }
+ };
+
+ var bindReader = function(freader, fname) {
+ freader.onloadend = function(event) {
+ if (event.target.readyState == FileReader.DONE)
+ return dedupAndAdd(event.target.result, fname);
+ else
+ return null;
+ };
+ };
+
+ /**
+ * Hash the buffer with SHA-1, SHA-1_GIT, SHA-256
+ * Args:
+ * buffer: the buffer to hash
+ * fname: the file name corresponding to the buffer
+ * Returns:
+ * a dict of algo_hash: hash
+ */
+ var hashBuffer = function (buffer, fname) {
+ function str2ab(header) {
+ var buf = new ArrayBuffer(header.length);
+ var view = new Uint8Array(buf); // byte view, all we need is ASCII
+ for (var idx = 0, len=header.length; idx < len; idx++)
+ view[idx] = header.charCodeAt(idx);
+ return buf;
+ }
+
+ var content_array = CryptoJS.lib.WordArray.create(buffer);
+ var git_hd_str = 'blob ' + buffer.byteLength + '\0';
+ var git_hd_buffer = str2ab(git_hd_str);
+ var git_hd_array = CryptoJS.lib.WordArray.create(git_hd_buffer);
+
+ var sha1 = CryptoJS.SHA1(content_array);
+ var sha256 = CryptoJS.SHA256(content_array);
+ var sha1_git = CryptoJS.SHA1(git_hd_array.concat(content_array));
+ return {
+ 'sha1': sha1 + '',
+ 'sha256': sha256 + '',
+ 'sha1_git': sha1_git + ''
+ };
+ };
+
+ /**
+ * Hash the buffer and add it to the form if it is unique
+ * If not, display which file has the same content
+ * Args:
+ * buffer: the buffer to hash
+ * fname: the file name corresponding to the buffer
+ */
+ var dedupAndAdd = function(buffer, fname) {
+ var hashes = hashBuffer(buffer);
+ var has_duplicate = false;
+ for (var algo_s in hashes) {
+ if (self.hashed_already[algo_s][hashes[algo_s]] != undefined) {
+ // Duplicate content -- fileLister addition only, as duplicate
+ hashedListerElem.append($('<div>')
+ .addClass('span3')
+ .text(fname + ': duplicate of ' + self.hashed_already[algo_s][hashes[algo_s]]));
+ has_duplicate = true;
+ break;
+ }
+ }
+ // First file read with this content -- fileLister and form addition
+ if (!has_duplicate) {
+ // Add to hashed list
+ for (var algo_c in self.hashed_already)
+ self.hashed_already[algo_c][hashes[algo_c]] = fname;
+ hashedListerElem.append($('<div>')
+ .addClass('span3')
+ .text(fname));
+ var hashstring = JSON.stringify(hashes).replace('\"', '\'');
+ self.fileForm.append($("<input>", {type: 'hidden',
+ class: 'search-hidden',
+ name: fname,
+ value: hashes['sha1']}// hashstring}
+ ));
+
+ }
+ };
+ };
+};

File Metadata

Mime Type
text/plain
Expires
Dec 21 2024, 6:56 PM (11 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3220824

Event Timeline