Implement comprehensive SRP Buffer polyfill to fix verification errors
This commit is contained in:
parent
6289577898
commit
7f7ae4e8bf
384
start.sh
384
start.sh
@ -679,8 +679,10 @@ chmod 644 /app/data/web/runtime-config.js
|
||||
|
||||
# Create a custom URL patch file to fix the URL constructor error
|
||||
echo "==> Creating URL and SRP patch file"
|
||||
cat << EOF > /app/data/web/ente-patches.js
|
||||
cat > /app/data/web/photos/static/ente-patches.js << 'ENDPATCHES'
|
||||
(function() {
|
||||
console.log('Applying Ente URL and SRP patches...');
|
||||
|
||||
// Save original URL constructor
|
||||
const originalURL = window.URL;
|
||||
|
||||
@ -710,102 +712,364 @@ cat << EOF > /app/data/web/ente-patches.js
|
||||
}
|
||||
};
|
||||
|
||||
// More robust Buffer implementation for SRP
|
||||
window.Buffer = window.Buffer || {
|
||||
// Comprehensive Buffer polyfill for SRP
|
||||
const originalBuffer = window.Buffer;
|
||||
window.Buffer = {
|
||||
from: function(data, encoding) {
|
||||
// Handle undefined data - critical fix
|
||||
if (data === undefined) {
|
||||
console.warn('Buffer.from called with undefined data, creating empty buffer');
|
||||
return {
|
||||
data: '',
|
||||
// Debug logging for the SRP calls
|
||||
console.debug('Buffer.from called with:',
|
||||
typeof data,
|
||||
data === undefined ? 'undefined' :
|
||||
data === null ? 'null' :
|
||||
Array.isArray(data) ? 'array[' + data.length + ']' :
|
||||
'value',
|
||||
'encoding:', encoding);
|
||||
|
||||
// Handle undefined/null data - critical fix
|
||||
if (data === undefined || data === null) {
|
||||
console.warn('Buffer.from called with ' + (data === undefined ? 'undefined' : 'null') + ' data, creating empty buffer');
|
||||
const result = {
|
||||
data: new Uint8Array(0),
|
||||
length: 0,
|
||||
toString: function() { return ''; }
|
||||
toString: function(enc) { return ''; }
|
||||
};
|
||||
|
||||
// Add additional methods that SRP might use
|
||||
result.slice = function() { return Buffer.from([]); };
|
||||
result.readUInt32BE = function() { return 0; };
|
||||
result.writeUInt32BE = function() { return result; };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Special case for hex strings - very important for SRP
|
||||
if (typeof data === 'string' && encoding === 'hex') {
|
||||
// Convert hex string to byte array
|
||||
const bytes = [];
|
||||
for (let i = 0; i < data.length; i += 2) {
|
||||
if (data.length - i >= 2) {
|
||||
bytes.push(parseInt(data.substr(i, 2), 16));
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
data: new Uint8Array(bytes),
|
||||
length: bytes.length,
|
||||
toString: function(enc) {
|
||||
if (enc === 'hex' || !enc) {
|
||||
return data; // Return original hex string
|
||||
}
|
||||
return bytes.map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
};
|
||||
|
||||
// Add methods needed by SRP
|
||||
result.slice = function(start, end) {
|
||||
const slicedData = bytes.slice(start, end);
|
||||
return Buffer.from(slicedData.map(b => b.toString(16).padStart(2, '0')).join(''), 'hex');
|
||||
};
|
||||
|
||||
result.readUInt32BE = function(offset = 0) {
|
||||
let value = 0;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
value = (value << 8) + (offset + i < bytes.length ? bytes[offset + i] : 0);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
result.writeUInt32BE = function(value, offset = 0) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (offset + i < bytes.length) {
|
||||
bytes[offset + 3 - i] = value & 0xFF;
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle string data
|
||||
if (typeof data === 'string') {
|
||||
return {
|
||||
data: data,
|
||||
length: data.length,
|
||||
const bytes = Array.from(data).map(c => c.charCodeAt(0));
|
||||
const result = {
|
||||
data: new Uint8Array(bytes),
|
||||
length: bytes.length,
|
||||
toString: function(enc) {
|
||||
if (enc === 'hex' && encoding === 'hex') {
|
||||
// Return the original hex string
|
||||
return data;
|
||||
if (enc === 'hex') {
|
||||
return bytes.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
// Add SRP methods
|
||||
result.slice = function(start, end) {
|
||||
return Buffer.from(data.slice(start, end));
|
||||
};
|
||||
|
||||
result.readUInt32BE = function(offset = 0) {
|
||||
let value = 0;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
value = (value << 8) + (offset + i < bytes.length ? bytes[offset + i] : 0);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
result.writeUInt32BE = function(value, offset = 0) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (offset + i < bytes.length) {
|
||||
bytes[offset + 3 - i] = value & 0xFF;
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle array/buffer data
|
||||
if (Array.isArray(data) || ArrayBuffer.isView(data)) {
|
||||
return {
|
||||
data: data,
|
||||
length: data.length,
|
||||
toString: function() {
|
||||
return Array.from(data).map(b => String.fromCharCode(b)).join('');
|
||||
if (Array.isArray(data) || ArrayBuffer.isView(data) || (data instanceof ArrayBuffer)) {
|
||||
const bytes = Array.isArray(data) ? data : new Uint8Array(data.buffer || data);
|
||||
const result = {
|
||||
data: new Uint8Array(bytes),
|
||||
length: bytes.length,
|
||||
toString: function(enc) {
|
||||
if (enc === 'hex') {
|
||||
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
return Array.from(bytes).map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
};
|
||||
|
||||
// Add SRP methods
|
||||
result.slice = function(start, end) {
|
||||
return Buffer.from(bytes.slice(start, end));
|
||||
};
|
||||
|
||||
result.readUInt32BE = function(offset = 0) {
|
||||
let value = 0;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
value = (value << 8) + (offset + i < bytes.length ? bytes[offset + i] : 0);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
result.writeUInt32BE = function(value, offset = 0) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (offset + i < bytes.length) {
|
||||
bytes[offset + 3 - i] = value & 0xFF;
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return {
|
||||
data: data || '',
|
||||
length: (data && data.length) || 0,
|
||||
toString: function() { return ''; }
|
||||
// Handle object data (last resort)
|
||||
if (typeof data === 'object') {
|
||||
console.warn('Buffer.from called with object type', data);
|
||||
const result = {
|
||||
data: data,
|
||||
length: data.length || 0,
|
||||
toString: function() { return JSON.stringify(data); }
|
||||
};
|
||||
|
||||
// Add SRP methods
|
||||
result.slice = function() { return Buffer.from({}); };
|
||||
result.readUInt32BE = function() { return 0; };
|
||||
result.writeUInt32BE = function() { return result; };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Default fallback for any other type
|
||||
console.warn('Buffer.from called with unsupported type:', typeof data);
|
||||
const result = {
|
||||
data: new Uint8Array(0),
|
||||
length: 0,
|
||||
toString: function() { return ''; },
|
||||
slice: function() { return Buffer.from([]); },
|
||||
readUInt32BE: function() { return 0; },
|
||||
writeUInt32BE: function() { return result; }
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
isBuffer: function(obj) { return obj && obj.data !== undefined; },
|
||||
alloc: function(size) {
|
||||
const arr = new Array(size).fill(0);
|
||||
return {
|
||||
data: arr,
|
||||
|
||||
isBuffer: function(obj) {
|
||||
return obj && (obj.data !== undefined || (originalBuffer && originalBuffer.isBuffer && originalBuffer.isBuffer(obj)));
|
||||
},
|
||||
|
||||
alloc: function(size, fill = 0) {
|
||||
const bytes = new Array(size).fill(fill);
|
||||
const result = {
|
||||
data: new Uint8Array(bytes),
|
||||
length: size,
|
||||
toString: function() { return ''; }
|
||||
};
|
||||
},
|
||||
concat: function(list) {
|
||||
// Simple implementation that handles our use case
|
||||
return {
|
||||
data: list.map(b => b.data).join(''),
|
||||
length: list.reduce((acc, b) => acc + (b.length || 0), 0),
|
||||
toString: function() {
|
||||
return list.map(b => b.toString()).join('');
|
||||
toString: function(enc) {
|
||||
if (enc === 'hex') {
|
||||
return bytes.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
return bytes.map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
};
|
||||
|
||||
// Add SRP methods
|
||||
result.slice = function(start, end) {
|
||||
return Buffer.from(bytes.slice(start, end));
|
||||
};
|
||||
|
||||
result.readUInt32BE = function(offset = 0) {
|
||||
let value = 0;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
value = (value << 8) + (offset + i < bytes.length ? bytes[offset + i] : 0);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
result.writeUInt32BE = function(value, offset = 0) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (offset + i < bytes.length) {
|
||||
bytes[offset + 3 - i] = value & 0xFF;
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
concat: function(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
|
||||
// Combine all buffers into one
|
||||
const totalLength = list.reduce((acc, buf) => acc + (buf ? (buf.length || 0) : 0), 0);
|
||||
const combinedArray = new Uint8Array(totalLength);
|
||||
|
||||
let offset = 0;
|
||||
for (const buf of list) {
|
||||
if (buf && buf.data) {
|
||||
const data = buf.data instanceof Uint8Array ? buf.data : new Uint8Array(buf.data);
|
||||
combinedArray.set(data, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
data: combinedArray,
|
||||
length: totalLength,
|
||||
toString: function(enc) {
|
||||
if (enc === 'hex') {
|
||||
return Array.from(combinedArray).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
return Array.from(combinedArray).map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
};
|
||||
|
||||
// Add SRP methods
|
||||
result.slice = function(start, end) {
|
||||
const slicedData = combinedArray.slice(start, end);
|
||||
return Buffer.from(slicedData);
|
||||
};
|
||||
|
||||
result.readUInt32BE = function(offset = 0) {
|
||||
let value = 0;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
value = (value << 8) + (offset + i < combinedArray.length ? combinedArray[offset + i] : 0);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
result.writeUInt32BE = function(value, offset = 0) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (offset + i < combinedArray.length) {
|
||||
combinedArray[offset + 3 - i] = value & 0xFF;
|
||||
value >>>= 8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Add missing crypto methods that SRP might need
|
||||
if (window.crypto && !window.crypto.randomBytes) {
|
||||
window.crypto.randomBytes = function(size) {
|
||||
const array = new Uint8Array(size);
|
||||
window.crypto.getRandomValues(array);
|
||||
return {
|
||||
data: array,
|
||||
length: size,
|
||||
toString: function(encoding) {
|
||||
if (encoding === 'hex') {
|
||||
return Array.from(array).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
return Array.from(array).map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
if (window.crypto) {
|
||||
if (!window.crypto.randomBytes) {
|
||||
window.crypto.randomBytes = function(size) {
|
||||
const array = new Uint8Array(size);
|
||||
window.crypto.getRandomValues(array);
|
||||
return Buffer.from(array);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Add cryptographic hash functions if needed
|
||||
if (!window.crypto.createHash) {
|
||||
window.crypto.createHash = function(algorithm) {
|
||||
return {
|
||||
update: function(data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
},
|
||||
digest: async function(encoding) {
|
||||
// Use the SubtleCrypto API for actual hashing
|
||||
const dataBuffer = typeof this.data === 'string' ?
|
||||
new TextEncoder().encode(this.data) :
|
||||
this.data;
|
||||
|
||||
let hashBuffer;
|
||||
try {
|
||||
if (algorithm === 'sha256') {
|
||||
hashBuffer = await window.crypto.subtle.digest('SHA-256', dataBuffer);
|
||||
} else if (algorithm === 'sha1') {
|
||||
hashBuffer = await window.crypto.subtle.digest('SHA-1', dataBuffer);
|
||||
} else {
|
||||
console.error('Unsupported hash algorithm:', algorithm);
|
||||
return Buffer.alloc(32); // Return empty buffer as fallback
|
||||
}
|
||||
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
|
||||
if (encoding === 'hex') {
|
||||
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
return Buffer.from(hashArray);
|
||||
} catch (e) {
|
||||
console.error('Hash calculation failed:', e);
|
||||
return Buffer.alloc(32); // Return empty buffer as fallback
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Patch the SRP implementation for browser compatibility
|
||||
if (window.process) {
|
||||
// Add any missing process methods
|
||||
window.process.nextTick = window.process.nextTick || function(fn) {
|
||||
setTimeout(fn, 0);
|
||||
if (!window.process) {
|
||||
window.process = {
|
||||
env: {
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Add any missing process methods
|
||||
window.process.nextTick = window.process.nextTick || function(fn) {
|
||||
setTimeout(fn, 0);
|
||||
};
|
||||
|
||||
console.log('Ente URL and SRP patches applied successfully');
|
||||
})();
|
||||
EOF
|
||||
ENDPATCHES
|
||||
|
||||
# Create the static HTML files with scripts pre-injected
|
||||
for app_dir in photos accounts auth cast; do
|
||||
|
Loading…
x
Reference in New Issue
Block a user