Appearance
System Update
Uploads and initiates a system update process using a provided update file. This endpoint allows administrators to upload .update files to update the IPCom system.
Request
http
POST /api/updateAuthentication Required: Must include JWT token in Authorization header.
Required Scope: None (any authenticated user can access this endpoint)
Content-Type: multipart/form-data
Form Field:
file: The update file (must be a.updatefile)
Request Examples
Upload Update File
bash
curl -X POST "http://your-server-ip:port/api/update" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "file=@ipcom_v5.0.0_B40.update"Using JavaScript with FormData
javascript
const fileInput = document.getElementById('updateFile');
const file = fileInput.files[0];
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/update', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});Using JavaScript with File Upload
javascript
async function uploadUpdateFile(file, token) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/api/update', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
const result = await response.json();
console.log('Update initiated successfully');
return result;
} catch (error) {
console.error('Failed to upload update:', error);
throw error;
}
}Response
Success (200 OK)
json
{
"success": true
}Error Responses
Note: Error responses are returned as plain text, not JSON.
400 Bad Request
No file providedFile upload failed401 Unauthorized
NOT_LOGGED_IN403 Forbidden
FORBIDDEN405 Method Not Allowed
Method Not Allowed500 Internal Server Error
Extraction errorScript execution failedFailure during file handlingUpdate Process
Update Workflow
- File Upload: Update file is uploaded via multipart form data
- Validation: System validates the uploaded
.updatefile - Preparation: Update scripts and files are prepared
- Initiation: Update process is initiated asynchronously
- System Restart: System may restart or shutdown during update
Asynchronous Processing
- Immediate Response: Endpoint returns success immediately after upload
- Background Processing: Actual update process runs asynchronously
- System Availability: System may become unavailable during update
- No Progress Updates: Endpoint doesn't provide update progress information
Usage Examples
Basic Update Upload
javascript
async function uploadUpdate(token, updateFile) {
const formData = new FormData();
formData.append('file', updateFile);
try {
console.log('Uploading system update...');
const response = await fetch('/api/update', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Update upload failed: ${errorText}`);
}
const result = await response.json();
console.log('✓ Update upload successful');
console.log('⚠ System update initiated - system may restart');
return result;
} catch (error) {
console.error('✗ Update upload failed:', error);
throw error;
}
}Update Manager Class
javascript
class UpdateManager {
constructor(token) {
this.token = token;
}
async uploadUpdate(file, onProgress = null) {
// Validate file
if (!file) {
throw new Error('No update file provided');
}
if (!file.name.endsWith('.update')) {
throw new Error('Invalid file type. Must be a .update file');
}
const formData = new FormData();
formData.append('file', file);
try {
// Log update initiation
await this.logUpdateEvent('update_initiated', file.name);
const response = await fetch('/api/update', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`
},
body: formData
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Upload failed: ${errorText}`);
}
const result = await response.json();
// Log successful upload
await this.logUpdateEvent('update_uploaded', file.name);
console.log('✓ Update uploaded successfully');
console.log('⚠ System update process initiated');
console.log('⚠ System may restart or become unavailable');
return result;
} catch (error) {
// Log failed upload
await this.logUpdateEvent('update_failed', file.name, error.message);
console.error('✗ Update upload failed:', error.message);
throw error;
}
}
async validateUpdateFile(file) {
const validations = [];
// Check file presence
if (!file) {
validations.push('No file selected');
} else {
// Check file extension
if (!file.name.endsWith('.update')) {
validations.push('File must have .update extension');
}
// Check file size (reasonable limits)
const maxSize = 500 * 1024 * 1024; // 500MB
if (file.size > maxSize) {
validations.push('File size too large (max 500MB)');
}
if (file.size === 0) {
validations.push('File is empty');
}
}
return {
isValid: validations.length === 0,
errors: validations
};
}
async logUpdateEvent(event, filename, error = null) {
const logEntry = {
timestamp: new Date().toISOString(),
event: event,
filename: filename,
error: error,
user: this.getCurrentUser()
};
console.log('UPDATE_EVENT:', JSON.stringify(logEntry));
// Save to local storage
try {
const logs = JSON.parse(localStorage.getItem('updateLogs') || '[]');
logs.push(logEntry);
localStorage.setItem('updateLogs', JSON.stringify(logs));
} catch (storageError) {
console.warn('Could not save update log locally:', storageError.message);
}
}
getCurrentUser() {
try {
const token = localStorage.getItem('authToken');
const payload = JSON.parse(atob(token.split('.')[1]));
return payload.username || payload.sub;
} catch {
return 'unknown';
}
}
}
// Usage
const updateManager = new UpdateManager(authToken);
// File selection and upload
const fileInput = document.getElementById('updateFile');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
// Validate file
const validation = await updateManager.validateUpdateFile(file);
if (!validation.isValid) {
console.error('File validation failed:', validation.errors);
return;
}
// Upload update
try {
await updateManager.uploadUpdate(file);
} catch (error) {
console.error('Upload failed:', error.message);
}
}
});Update UI Component
javascript
class UpdateUploadUI {
constructor(updateManager) {
this.updateManager = updateManager;
this.createUI();
}
createUI() {
const container = document.getElementById('update-container');
container.innerHTML = `
<div class="update-upload">
<h3>System Update</h3>
<div class="file-input-wrapper">
<input type="file" id="updateFile" accept=".update" />
<label for="updateFile">Select Update File (.update)</label>
</div>
<div class="file-info" id="fileInfo" style="display: none;"></div>
<div class="validation-errors" id="validationErrors" style="display: none;"></div>
<button id="uploadBtn" disabled>Upload Update</button>
<div class="progress" id="uploadProgress" style="display: none;">
<div class="progress-bar"></div>
<span class="progress-text">Uploading...</span>
</div>
<div class="warnings" id="updateWarnings" style="display: none;">
<h4>⚠ Important Warnings:</h4>
<ul>
<li>System will restart during update process</li>
<li>All services will be temporarily unavailable</li>
<li>Ensure no critical operations are running</li>
<li>Update process cannot be cancelled once started</li>
</ul>
</div>
</div>
`;
this.bindEvents();
}
bindEvents() {
const fileInput = document.getElementById('updateFile');
const uploadBtn = document.getElementById('uploadBtn');
fileInput.addEventListener('change', (event) => {
this.handleFileSelection(event.target.files[0]);
});
uploadBtn.addEventListener('click', () => {
this.handleUpload();
});
}
async handleFileSelection(file) {
const fileInfo = document.getElementById('fileInfo');
const validationErrors = document.getElementById('validationErrors');
const uploadBtn = document.getElementById('uploadBtn');
const warnings = document.getElementById('updateWarnings');
if (!file) {
fileInfo.style.display = 'none';
validationErrors.style.display = 'none';
uploadBtn.disabled = true;
warnings.style.display = 'none';
return;
}
// Show file info
fileInfo.innerHTML = `
<strong>Selected File:</strong> ${file.name}<br>
<strong>Size:</strong> ${this.formatFileSize(file.size)}<br>
<strong>Type:</strong> ${file.type || 'Unknown'}
`;
fileInfo.style.display = 'block';
// Validate file
const validation = await this.updateManager.validateUpdateFile(file);
if (!validation.isValid) {
validationErrors.innerHTML = `
<strong>Validation Errors:</strong>
<ul>
${validation.errors.map(error => `<li>${error}</li>`).join('')}
</ul>
`;
validationErrors.style.display = 'block';
uploadBtn.disabled = true;
warnings.style.display = 'none';
} else {
validationErrors.style.display = 'none';
uploadBtn.disabled = false;
warnings.style.display = 'block';
}
this.selectedFile = file;
}
async handleUpload() {
if (!this.selectedFile) {
return;
}
const uploadBtn = document.getElementById('uploadBtn');
const progress = document.getElementById('uploadProgress');
// Show confirmation dialog
const confirmed = confirm(
'Are you sure you want to start the system update?\n\n' +
'WARNING: The system will restart and become temporarily unavailable.\n' +
'This action cannot be undone once started.'
);
if (!confirmed) {
return;
}
try {
uploadBtn.disabled = true;
progress.style.display = 'block';
await this.updateManager.uploadUpdate(this.selectedFile);
// Show success message
progress.innerHTML = `
<div class="success-message">
<h4>✓ Update Uploaded Successfully</h4>
<p>System update process has been initiated.</p>
<p><strong>The system will restart shortly.</strong></p>
<p>Please wait for the system to come back online.</p>
</div>
`;
} catch (error) {
// Show error message
progress.innerHTML = `
<div class="error-message">
<h4>✗ Upload Failed</h4>
<p>${error.message}</p>
</div>
`;
uploadBtn.disabled = false;
}
}
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
}
// Initialize UI
const updateUI = new UpdateUploadUI(updateManager);Error Handling and Recovery
javascript
class UpdateErrorHandler {
constructor(updateManager) {
this.updateManager = updateManager;
}
async handleUpdateError(error, context) {
const errorInfo = {
message: error.message,
context: context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
};
console.error('UPDATE_ERROR:', errorInfo);
// Categorize error types
if (error.message.includes('No file provided')) {
return this.handleFileError('No file was selected for upload');
} else if (error.message.includes('File upload failed')) {
return this.handleUploadError('File upload process failed');
} else if (error.message.includes('Extraction error')) {
return this.handleFileError('Update file could not be extracted');
} else if (error.message.includes('Script execution failed')) {
return this.handleSystemError('Update script execution failed');
} else if (error.message.includes('Method Not Allowed')) {
return this.handleRequestError('Invalid request method - use POST');
} else {
return this.handleGenericError(error.message);
}
}
handleFileError(message) {
return {
type: 'file_error',
message: message,
suggestions: [
'Verify the update file is not corrupted',
'Ensure the file has .update extension',
'Try downloading the update file again',
'Contact support if the problem persists'
]
};
}
handleUploadError(message) {
return {
type: 'upload_error',
message: message,
suggestions: [
'Check network connection',
'Verify sufficient disk space on server',
'Try uploading again',
'Use a smaller update file if available'
]
};
}
handleSystemError(message) {
return {
type: 'system_error',
message: message,
suggestions: [
'Contact system administrator',
'Verify system configuration',
'Check server logs for details',
'Restart system services if possible'
]
};
}
handleRequestError(message) {
return {
type: 'request_error',
message: message,
suggestions: [
'Verify API endpoint is correct',
'Check request headers and method',
'Ensure authentication token is valid',
'Review API documentation'
]
};
}
handleGenericError(message) {
return {
type: 'generic_error',
message: message,
suggestions: [
'Try the operation again',
'Check system status',
'Contact support with error details',
'Review recent system changes'
]
};
}
}
// Usage with error handling
async function safeUpdateUpload(file, token) {
const updateManager = new UpdateManager(token);
const errorHandler = new UpdateErrorHandler(updateManager);
try {
return await updateManager.uploadUpdate(file);
} catch (error) {
const errorInfo = await errorHandler.handleUpdateError(error, 'update_upload');
console.error(`Error Type: ${errorInfo.type}`);
console.error(`Message: ${errorInfo.message}`);
console.error('Suggestions:', errorInfo.suggestions);
throw error;
}
}Security Considerations
Access Control
- Authentication Required: Users must be authenticated to upload updates
- No Specific Scope: Any authenticated user can upload updates
- Administrative Use: Intended for administrative system updates
Update Safety
javascript
async function secureUpdateUpload(file, token, userContext) {
// Additional security checks
if (!userContext.isAdmin) {
console.warn('Non-admin user attempting update upload');
// Consider implementing additional restrictions
}
// Verify file integrity if possible
if (file.size > 1024 * 1024 * 1024) { // 1GB limit
throw new Error('Update file too large - possible security risk');
}
// Log the update attempt
console.log('UPDATE_SECURITY_LOG:', {
user: userContext.username,
filename: file.name,
fileSize: file.size,
timestamp: new Date().toISOString(),
ipAddress: userContext.ipAddress
});
return await uploadUpdate(token, file);
}System Impact
- Service Interruption: System will restart during update
- Data Safety: Ensure all critical data is saved before update
- Backup Recommended: Create system backup before major updates
- Recovery Planning: Have rollback procedures ready
Important Notes
- Authentication Required: Users must be authenticated but no specific scope is needed
- File Type Restriction: Only
.updatefiles are accepted - Plain Text Errors: Error responses are plain text, not JSON
- Asynchronous Process: Update process runs in background after upload
- System Restart: System may restart or shutdown during update
- No Progress Updates: Endpoint doesn't provide update progress information
- Administrative Use: Intended for system administrators and maintenance
- One-way Process: Update cannot be cancelled once initiated
- Network Considerations: Large files may require stable network connection
- System Requirements: Ensure sufficient disk space and system resources