mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
feat(GUI): enable "unsafe" mode (#578)
This setting makes Etcher not filter non-removable drives, allowing you to arbitrarily write to your system drives. This is a dangerous option, therefore we present it in a separate section of the settings page, and show an informative confirmation dialog. Change-Type: minor Changelog-Entry: Add an "unsafe" option to bypass drive protection. Fixes: https://github.com/resin-io/etcher/issues/480 Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
parent
e696d0722d
commit
a3dc8624b1
@ -5945,6 +5945,9 @@ html {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px; }
|
||||
|
||||
.space-top-large, .page-settings .subtitle {
|
||||
margin-top: 30px; }
|
||||
|
||||
.space-top-medium {
|
||||
margin-top: 15px; }
|
||||
|
||||
@ -5952,6 +5955,9 @@ html {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px; }
|
||||
|
||||
.space-bottom-medium, .page-settings .subtitle {
|
||||
margin-bottom: 15px; }
|
||||
|
||||
.space-bottom-large {
|
||||
margin-bottom: 30px; }
|
||||
|
||||
@ -6515,6 +6521,36 @@ button.btn:focus, button.progress-button:focus {
|
||||
.page-settings .checkbox input[type="checkbox"]:not(:checked) + * {
|
||||
color: #ddd; }
|
||||
|
||||
.modal-settings-dangerous-modal {
|
||||
max-width: 50%; }
|
||||
.modal-settings-dangerous-modal .modal-header {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
color: #555555;
|
||||
text-transform: initial;
|
||||
font-size: 15px;
|
||||
border-bottom: none;
|
||||
padding: 0 0 15px; }
|
||||
.modal-settings-dangerous-modal .modal-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; }
|
||||
.modal-settings-dangerous-modal .modal-title .glyphicon, .modal-settings-dangerous-modal .modal-title .tick {
|
||||
margin-right: 3px;
|
||||
color: #d9534f; }
|
||||
.modal-settings-dangerous-modal .modal-content {
|
||||
padding: 25px 30px;
|
||||
height: 220px; }
|
||||
.modal-settings-dangerous-modal .modal-body {
|
||||
padding: 0; }
|
||||
.modal-settings-dangerous-modal .modal-footer {
|
||||
padding: 0;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eeeeee;
|
||||
display: flex; }
|
||||
.modal-settings-dangerous-modal .modal-footer > .btn, .modal-settings-dangerous-modal .modal-footer > .progress-button {
|
||||
flex-basis: 50%; }
|
||||
|
||||
/*
|
||||
* Copyright 2016 Resin.io
|
||||
*
|
||||
|
@ -37,6 +37,7 @@ const DEFAULT_STATE = Immutable.fromJS({
|
||||
speed: 0
|
||||
},
|
||||
settings: {
|
||||
unsafeMode: false,
|
||||
errorReporting: true,
|
||||
unmountOnSuccess: true,
|
||||
validateWriteOnSuccess: true,
|
||||
|
@ -27,9 +27,11 @@ const EventEmitter = require('events').EventEmitter;
|
||||
const drivelist = require('drivelist');
|
||||
|
||||
const MODULE_NAME = 'Etcher.Modules.DriveScanner';
|
||||
const driveScanner = angular.module(MODULE_NAME, []);
|
||||
const driveScanner = angular.module(MODULE_NAME, [
|
||||
require('../models/settings')
|
||||
]);
|
||||
|
||||
driveScanner.factory('DriveScannerService', () => {
|
||||
driveScanner.factory('DriveScannerService', (SettingsModel) => {
|
||||
const DRIVE_SCANNER_INTERVAL_MS = 2000;
|
||||
const emitter = new EventEmitter();
|
||||
|
||||
@ -38,6 +40,10 @@ driveScanner.factory('DriveScannerService', () => {
|
||||
return Rx.Observable.fromNodeCallback(drivelist.list)();
|
||||
})
|
||||
.map((drives) => {
|
||||
if (SettingsModel.get('unsafeMode')) {
|
||||
return drives;
|
||||
}
|
||||
|
||||
return _.reject(drives, (drive) => {
|
||||
return drive.system;
|
||||
});
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2016 Resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function($uibModalInstance, message) {
|
||||
|
||||
/**
|
||||
* @summary Modal message
|
||||
* @property
|
||||
* @public
|
||||
*/
|
||||
this.message = message;
|
||||
|
||||
/**
|
||||
* @summary Reject the dangerous setting
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @example
|
||||
* SettingsDangerousModalController.reject();
|
||||
*/
|
||||
this.reject = () => {
|
||||
$uibModalInstance.close(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Accept the dangerous setting
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @example
|
||||
* SettingsDangerousModalController.accept();
|
||||
*/
|
||||
this.accept = () => {
|
||||
$uibModalInstance.close(true);
|
||||
};
|
||||
|
||||
};
|
@ -16,14 +16,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(SettingsModel) {
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = function($uibModal, SettingsModel) {
|
||||
|
||||
/**
|
||||
* @summary Refresh current settings
|
||||
* @function
|
||||
* @public
|
||||
*/
|
||||
this.refreshSettings = () => {
|
||||
this.currentData = SettingsModel.getAll();
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Current settings value
|
||||
* @type Object
|
||||
* @public
|
||||
*/
|
||||
this.currentData = SettingsModel.getAll();
|
||||
this.currentData = {};
|
||||
this.refreshSettings();
|
||||
|
||||
/**
|
||||
* @summary Settings model
|
||||
@ -32,4 +44,36 @@ module.exports = function(SettingsModel) {
|
||||
*/
|
||||
this.model = SettingsModel;
|
||||
|
||||
/**
|
||||
* @summary Enable a dangerous setting
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} name - setting name
|
||||
* @param {String} message - danger message
|
||||
* @returns {Undefined}
|
||||
*
|
||||
* @example
|
||||
* SettingsController.enableDangerousSetting('unsafeMode', 'Don\'t do this!');
|
||||
*/
|
||||
this.enableDangerousSetting = (name, message) => {
|
||||
if (!this.currentData[name]) {
|
||||
this.model.set(name, false);
|
||||
return this.refreshSettings();
|
||||
}
|
||||
|
||||
$uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: './pages/settings/templates/settings-dangerous-modal.tpl.html',
|
||||
controller: 'SettingsDangerousModalController as modal',
|
||||
size: 'settings-dangerous-modal',
|
||||
resolve: {
|
||||
message: _.constant(message)
|
||||
}
|
||||
}).result.then((userAccepted) => {
|
||||
this.model.set(name, Boolean(userAccepted));
|
||||
this.refreshSettings();
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -28,6 +28,7 @@ const SettingsPage = angular.module(MODULE_NAME, [
|
||||
]);
|
||||
|
||||
SettingsPage.controller('SettingsController', require('./controllers/settings'));
|
||||
SettingsPage.controller('SettingsDangerousModalController', require('./controllers/settings-dangerous-modal'));
|
||||
|
||||
SettingsPage.config(($stateProvider) => {
|
||||
$stateProvider
|
||||
|
@ -18,3 +18,52 @@
|
||||
color: $gray-light;
|
||||
}
|
||||
|
||||
.page-settings .subtitle {
|
||||
@extend .space-top-large;
|
||||
@extend .space-bottom-medium;
|
||||
}
|
||||
|
||||
.modal-settings-dangerous-modal {
|
||||
max-width: 50%;
|
||||
|
||||
.modal-header {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
color: $gray;
|
||||
text-transform: initial;
|
||||
font-size: 15px;
|
||||
border-bottom: none;
|
||||
padding: 0 0 15px;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.glyphicon {
|
||||
margin-right: 3px;
|
||||
color: $btn-danger-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
padding: 25px 30px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 0;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid $gray-lighter;
|
||||
display: flex;
|
||||
|
||||
& > .btn {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
||||
<span>Warning!</span>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to turn this on? {{ modal.message }}</p>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger"
|
||||
ng-click="modal.accept()">YES, CONTINUE</button>
|
||||
|
||||
<button class="btn btn-default"
|
||||
ng-click="modal.reject()">CANCEL</button>
|
||||
</div>
|
@ -30,4 +30,16 @@
|
||||
<span>Validate write on success</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3 class="subtitle">Advanced</h3>
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
ng-model="settings.currentData.unsafeMode"
|
||||
ng-change="settings.enableDangerousSetting('unsafeMode', 'You will be able to burn to your system drives.')">
|
||||
|
||||
<span>Unsafe mode <span class="label label-danger">DANGEROUS</span></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,6 +33,10 @@ $spacing-tiny: 5px;
|
||||
margin-bottom: $spacing-small;
|
||||
}
|
||||
|
||||
.space-top-large {
|
||||
margin-top: $spacing-large;
|
||||
}
|
||||
|
||||
.space-top-medium {
|
||||
margin-top: $spacing-medium;
|
||||
}
|
||||
@ -42,6 +46,10 @@ $spacing-tiny: 5px;
|
||||
margin-bottom: $spacing-large;
|
||||
}
|
||||
|
||||
.space-bottom-medium {
|
||||
margin-bottom: $spacing-medium;
|
||||
}
|
||||
|
||||
.space-bottom-large {
|
||||
margin-bottom: $spacing-large;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user