2 Commits

Author SHA1 Message Date
fc2fe70576 v0.2.1: Change SHA256 input to file upload field
- Replace SHA256 text input with file upload field for checksum files
- Add readChecksumFile() JavaScript function using FileReader API
- Support .sha256 and .txt checksum file formats
- Add Promise-based async handling for file reading
- Add localized error messages for checksum file validation
- Update translations (de_CH) with new strings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 17:13:27 +01:00
f5a1e55710 Add v0.2.0 release package
- wc-licensed-product-0.2.0.zip (486 KB)
- SHA256: 20d90f61721b4579cb979cd19b0262f3286c3510dcb0345fe5e8da2703e3836f

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 16:59:56 +01:00
9 changed files with 1221 additions and 1167 deletions

View File

@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.2.1] - 2026-01-22
### Changed
- SHA256 hash input changed from text field to file upload field
- Checksum files (.sha256 or .txt) can now be uploaded directly
- Improved user experience for version integrity verification
### Technical Details
- Added `readChecksumFile()` JavaScript function using FileReader API with Promise support
- Checksum file format supports both "hash filename" and plain "hash" formats
- Added localized error messages for checksum file validation
## [0.2.0] - 2026-01-22 ## [0.2.0] - 2026-01-22
### Added ### Added

View File

@@ -101,9 +101,38 @@
$('#selected_file_name').text(''); $('#selected_file_name').text('');
$('#remove-version-file-btn').hide(); $('#remove-version-file-btn').hide();
// Hide and clear SHA256 hash field // Hide and clear checksum file field
$('#sha256-hash-row').hide(); $('#sha256-hash-row').hide();
$('#new_file_hash').val(''); $('#new_checksum_file').val('');
},
/**
* Read checksum from uploaded file
* Supports formats: "hash filename" or just "hash"
*/
readChecksumFile: function(file) {
return new Promise(function(resolve, reject) {
if (!file) {
resolve('');
return;
}
var reader = new FileReader();
reader.onload = function(e) {
var content = e.target.result.trim();
// Extract hash from content (format: "hash filename" or just "hash")
var match = content.match(/^([a-fA-F0-9]{64})/);
if (match) {
resolve(match[1].toLowerCase());
} else {
reject(new Error(wcLicensedProductVersions.strings.invalidChecksumFile || 'Invalid checksum file format'));
}
};
reader.onerror = function() {
reject(new Error(wcLicensedProductVersions.strings.checksumReadError || 'Failed to read checksum file'));
};
reader.readAsText(file);
});
}, },
/** /**
@@ -134,13 +163,14 @@
addVersion: function(e) { addVersion: function(e) {
e.preventDefault(); e.preventDefault();
var self = WCLicensedProductVersions;
var $btn = $(this); var $btn = $(this);
var $spinner = $btn.siblings('.spinner'); var $spinner = $btn.siblings('.spinner');
var productId = $btn.data('product-id'); var productId = $btn.data('product-id');
var version = $('#new_version').val().trim(); var version = $('#new_version').val().trim();
var releaseNotes = $('#new_release_notes').val().trim(); var releaseNotes = $('#new_release_notes').val().trim();
var attachmentId = $('#new_attachment_id').val(); var attachmentId = $('#new_attachment_id').val();
var fileHash = $('#new_file_hash').val().trim(); var checksumFile = $('#new_checksum_file')[0].files[0];
// Validate version // Validate version
if (!version) { if (!version) {
@@ -156,45 +186,52 @@
$btn.prop('disabled', true); $btn.prop('disabled', true);
$spinner.addClass('is-active'); $spinner.addClass('is-active');
$.ajax({ // Read checksum file if provided, then submit
url: wcLicensedProductVersions.ajaxUrl, self.readChecksumFile(checksumFile).then(function(fileHash) {
type: 'POST', $.ajax({
data: { url: wcLicensedProductVersions.ajaxUrl,
action: 'wc_licensed_product_add_version', type: 'POST',
nonce: wcLicensedProductVersions.nonce, data: {
product_id: productId, action: 'wc_licensed_product_add_version',
version: version, nonce: wcLicensedProductVersions.nonce,
release_notes: releaseNotes, product_id: productId,
attachment_id: attachmentId, version: version,
file_hash: fileHash release_notes: releaseNotes,
}, attachment_id: attachmentId,
success: function(response) { file_hash: fileHash
if (response.success) { },
// Remove "no versions" row if present success: function(response) {
$('#versions-table tbody .no-versions').remove(); if (response.success) {
// Remove "no versions" row if present
$('#versions-table tbody .no-versions').remove();
// Add new row to table // Add new row to table
$('#versions-table tbody').prepend(response.data.html); $('#versions-table tbody').prepend(response.data.html);
// Clear form // Clear form
$('#new_version').val(''); $('#new_version').val('');
$('#new_release_notes').val(''); $('#new_release_notes').val('');
$('#new_attachment_id').val(''); $('#new_attachment_id').val('');
$('#selected_file_name').text(''); $('#selected_file_name').text('');
$('#remove-version-file-btn').hide(); $('#remove-version-file-btn').hide();
$('#sha256-hash-row').hide(); $('#sha256-hash-row').hide();
$('#new_file_hash').val(''); $('#new_checksum_file').val('');
} else { } else {
alert(response.data.message || wcLicensedProductVersions.strings.error); alert(response.data.message || wcLicensedProductVersions.strings.error);
}
},
error: function() {
alert(wcLicensedProductVersions.strings.error);
},
complete: function() {
$btn.prop('disabled', false);
$spinner.removeClass('is-active');
} }
}, });
error: function() { }).catch(function(error) {
alert(wcLicensedProductVersions.strings.error); alert(error.message);
}, $btn.prop('disabled', false);
complete: function() { $spinner.removeClass('is-active');
$btn.prop('disabled', false);
$spinner.removeClass('is-active');
}
}); });
}, },

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
20d90f61721b4579cb979cd19b0262f3286c3510dcb0345fe5e8da2703e3836f wc-licensed-product-0.2.0.zip

Binary file not shown.

View File

@@ -99,10 +99,10 @@ final class VersionAdminController
</td> </td>
</tr> </tr>
<tr id="sha256-hash-row" style="display: none;"> <tr id="sha256-hash-row" style="display: none;">
<th><label for="new_file_hash"><?php esc_html_e('SHA256 Hash', 'wc-licensed-product'); ?></label></th> <th><label for="new_checksum_file"><?php esc_html_e('Checksum File', 'wc-licensed-product'); ?></label></th>
<td> <td>
<input type="text" id="new_file_hash" name="new_file_hash" class="large-text" placeholder="<?php esc_attr_e('Enter SHA256 checksum...', 'wc-licensed-product'); ?>" pattern="[a-fA-F0-9]{64}" /> <input type="file" id="new_checksum_file" name="new_checksum_file" accept=".sha256,.txt" />
<p class="description"><?php esc_html_e('SHA256 checksum of the uploaded file (optional but recommended for integrity verification).', 'wc-licensed-product'); ?></p> <p class="description"><?php esc_html_e('Upload a SHA256 checksum file (.sha256 or .txt) to verify file integrity.', 'wc-licensed-product'); ?></p>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -218,6 +218,8 @@ final class VersionAdminController
'error' => __('An error occurred. Please try again.', 'wc-licensed-product'), 'error' => __('An error occurred. Please try again.', 'wc-licensed-product'),
'selectFile' => __('Select Download File', 'wc-licensed-product'), 'selectFile' => __('Select Download File', 'wc-licensed-product'),
'useThisFile' => __('Use this file', 'wc-licensed-product'), 'useThisFile' => __('Use this file', 'wc-licensed-product'),
'invalidChecksumFile' => __('Invalid checksum file format. File must contain a 64-character SHA256 hash.', 'wc-licensed-product'),
'checksumReadError' => __('Failed to read checksum file.', 'wc-licensed-product'),
], ],
]); ]);

View File

@@ -3,7 +3,7 @@
* Plugin Name: WooCommerce Licensed Product * Plugin Name: WooCommerce Licensed Product
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product * Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product
* Description: WooCommerce plugin to sell software products using license keys with domain-based validation. * Description: WooCommerce plugin to sell software products using license keys with domain-based validation.
* Version: 0.2.0 * Version: 0.2.1
* Author: Marco Graetsch * Author: Marco Graetsch
* Author URI: https://src.bundespruefstelle.ch/magdev * Author URI: https://src.bundespruefstelle.ch/magdev
* License: GPL-2.0-or-later * License: GPL-2.0-or-later
@@ -28,7 +28,7 @@ if (!defined('ABSPATH')) {
} }
// Plugin constants // Plugin constants
define('WC_LICENSED_PRODUCT_VERSION', '0.2.0'); define('WC_LICENSED_PRODUCT_VERSION', '0.2.1');
define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__); define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__);
define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__));