new: added defaults from/to local storage

This commit is contained in:
Simone Margaritelli
2024-04-06 10:19:07 -04:00
parent 07d219ba79
commit bf524cae2a
5 changed files with 567 additions and 470 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,6 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Arc</title> <title>Arc</title>
@@ -9,8 +10,8 @@
<meta name="description" content="Arc Secrets Manager"> <meta name="description" content="Arc Secrets Manager">
<meta name="author" content="Simone 'evilsocket' Margaritelli"> <meta name="author" content="Simone 'evilsocket' Margaritelli">
<link rel="shortcut icon" type="image/png" href="/img/logo.png?v=2.3"/> <link rel="shortcut icon" type="image/png" href="/img/logo.png?v=2.3" />
<link rel="apple-touch-icon" href="/img/logo.png?v=2.3"/> <link rel="apple-touch-icon" href="/img/logo.png?v=2.3" />
<link rel="stylesheet" href="/css/bootstrap/bootstrap.min.css"> <link rel="stylesheet" href="/css/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/css/bootstrap/bootstrap-datetimepicker.min.css"> <link rel="stylesheet" href="/css/bootstrap/bootstrap-datetimepicker.min.css">
@@ -56,6 +57,7 @@
<script type="text/javascript" src="/js/notify.js"></script> <script type="text/javascript" src="/js/notify.js"></script>
<script type="text/javascript" src="/js/app.js"></script> <script type="text/javascript" src="/js/app.js"></script>
</head> </head>
<body id="ngscope" ng-app="PM" ng-controller="PMController"> <body id="ngscope" ng-app="PM" ng-controller="PMController">
<div class="main-container container-fluid"> <div class="main-container container-fluid">
@@ -74,7 +76,8 @@
<!-- if user is logged instead --> <!-- if user is logged instead -->
<span ng-if="arc.IsLogged()" ng-switch on="arc.HasStore()"> <span ng-if="arc.IsLogged()" ng-switch on="arc.HasStore()">
<div class="notifications badge badge-pill badge-warning" ng-if="status.events.length" ng-include src="'/views/notifications.html'"> <div class="notifications badge badge-pill badge-warning" ng-if="status.events.length" ng-include
src="'/views/notifications.html'">
</div> </div>
<!-- no store selected, show available stores --> <!-- no store selected, show available stores -->
@@ -82,12 +85,17 @@
<ul id="stores_list" class="list-group stores-list"> <ul id="stores_list" class="list-group stores-list">
<li class="list-group-item"> <li class="list-group-item">
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-4">
<center class="action-button" ng-click="doLogout()"> <center class="action-button" ng-click="doLogout()">
<i class="fa fa-sign-out" aria-hidden="true"></i> <i class="fa fa-sign-out" aria-hidden="true"></i>
</center> </center>
</div> </div>
<div class="col-6" style="border-left: 1px solid #eee"> <div class="col-4">
<center class="action-button" ng-click="onSettings()">
<i class="fa fa-cog" aria-hidden="true"></i>
</center>
</div>
<div class="col-4" style="border-left: 1px solid #eee">
<center class="action-button" ng-click="onNewStore()"> <center class="action-button" ng-click="onNewStore()">
<i class="fa fa-file" aria-hidden="true"></i> <i class="fa fa-file" aria-hidden="true"></i>
</center> </center>
@@ -101,12 +109,14 @@
<small class="action-label"> <small class="action-label">
No stores found, create one using the <i class="fa fa-file" aria-hidden="true"></i> icon. No stores found, create one using the <i class="fa fa-file" aria-hidden="true"></i> icon.
</small> </small>
</li> </li>
<li class="list-group-item store-list-item" ng-repeat="s in stores" ng-click="onShowStore(s.id)"> <li class="list-group-item store-list-item" ng-repeat="s in stores" ng-click="onShowStore(s.id)">
<span ng-include src="'/views/store_list_item.html'"></span> <span ng-include src="'/views/store_list_item.html'"></span>
</li> </li>
</ul> </ul>
<div ng-include src="'/views/modals/settings.html'"></div>
</div> </div>
<!-- store selected, load records from it --> <!-- store selected, load records from it -->
@@ -121,19 +131,14 @@
</div> </div>
<h5 class="editable" id="store_title">{{ arc.store.title }}</h5> <h5 class="editable" id="store_title">{{ arc.store.title }}</h5>
<script type="text/javascript"> <script type="text/javascript">
$('#store_title').editable(function(v){ $('#store_title').editable(function (v) {
$('#ngscope').scope().onStoreTitleChanged(v); $('#ngscope').scope().onStoreTitleChanged(v);
}); });
</script> </script>
</div> </div>
<div class="col-6 input-group"> <div class="col-6 input-group">
<input <input type="text" id="search_filter" class="search-filter form-control border" ng-model="search"
type="text" ng-change="updateFilter()" placeholder="Search ..." />
id="search_filter"
class="search-filter form-control border"
ng-model="search"
ng-change="updateFilter()"
placeholder="Search ..."/>
</div> </div>
</div> </div>
<!-- will show session expire time when approaching 5 minutes left --> <!-- will show session expire time when approaching 5 minutes left -->
@@ -145,7 +150,7 @@
<div class="col-4"> <div class="col-4">
<center class="action-button" ng-click="onBack()"> <center class="action-button" ng-click="onBack()">
<i class="fa fa-chevron-left" aria-hidden="true"></i> <i class="fa fa-chevron-left" aria-hidden="true"></i>
</center> </center>
</div> </div>
<div class="col-4" style="border-left: 1px solid #eee"> <div class="col-4" style="border-left: 1px solid #eee">
<center class="action-button" ng-click="onDeleteStore()"> <center class="action-button" ng-click="onDeleteStore()">
@@ -164,15 +169,11 @@
<small class="action-label"> <small class="action-label">
No records found, create one using the <i class="fa fa-file" aria-hidden="true"></i> icon. No records found, create one using the <i class="fa fa-file" aria-hidden="true"></i> icon.
</small> </small>
</li> </li>
<li <li ng-repeat="r in arc.records | orderBy:['pinned','updated_at']:true" class="list-group-item"
ng-repeat="r in arc.records | orderBy:['pinned','updated_at']:true" id="secret_list_item_{{ r.id }}" ng-if="filterSecret(r)" ng-click="onShowSecret(r.id)"
class="list-group-item" ng-class="{'expired': isExpired(r), 'expiring': isExpiring(r), 'pinned': isPinned(r) }">
id="secret_list_item_{{ r.id }}"
ng-if="filterSecret(r)"
ng-click="onShowSecret(r.id)"
ng-class="{'expired': isExpired(r), 'expiring': isExpiring(r), 'pinned': isPinned(r) }">
<span ng-include src="'/views/secret_list_item.html?v=17'"></span> <span ng-include src="'/views/secret_list_item.html?v=17'"></span>
</li> </li>
</ul> </ul>
@@ -203,10 +204,11 @@
</span> </span>
<a href="https://github.com/evilsocket/arc">Arc</a> was made with <span style="color:red"></span> by <a href="https://github.com/evilsocket/arc">Arc</a> was made with <span style="color:red"></span> by
<a href="https://www.evilsocket.net/" target="_blank" >Simone 'evilsocket' Margaritelli</a> <a href="https://www.evilsocket.net/" target="_blank">Simone 'evilsocket' Margaritelli</a>
</small> </small>
</center> </center>
</footer> </footer>
</body> </body>
</html>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -9,51 +9,61 @@
var g_EntryCounter = 0; var g_EntryCounter = 0;
var REGISTERED_TYPES = [ var REGISTERED_TYPES = [
new URLEntry( "URL", "" ), new URLEntry("URL", ""),
new InputEntry( "Text Input", "" ), new InputEntry("Text Input", ""),
new CheckboxEntry( "Checkbox", "" ), new CheckboxEntry("Checkbox", ""),
new PasswordEntry( "Password", "" ), new PasswordEntry("Password", ""),
new TOTPEntry( "2FA", "" ), new TOTPEntry("2FA", ""),
new TextEntry( "Text", "" ), new TextEntry("Text", ""),
new MarkdownEntry( "Markdown", "" ), new MarkdownEntry("Markdown", ""),
new HTMLEntry( "HTML", "" ), new HTMLEntry("HTML", ""),
new CodeEntry( "Source Code", "" ), new CodeEntry("Source Code", ""),
new FileEntry( "File(s)", "" ), new FileEntry("File(s)", ""),
new BTCAddressEntry( "Bitcoin Address", "" ), new BTCAddressEntry("Bitcoin Address", ""),
]; ];
var REGISTERED_TEMPLATES = [ var REGISTERED_TEMPLATES = [
{ name: "Web Login", fields:[ {
new URLEntry( "URL", "https://" ), name: "Web Login", fields: [
new InputEntry( "Login", "" ), new URLEntry("URL", "https://"),
new PasswordEntry( "Password", "" ) new InputEntry("Login", "<default_login>"),
]}, new PasswordEntry("Password", "")
{ name: "Email Account", fields:[ ]
new InputEntry( "Provider", "" ), },
new InputEntry( "SMTP Server", "" ), {
new PasswordEntry( "SMTP Password", "" ), name: "Email Account", fields: [
new InputEntry( "IMAP Server", "" ), new InputEntry("Provider", ""),
new PasswordEntry( "IMAP Password", "" ) new InputEntry("SMTP Server", ""),
]}, new PasswordEntry("SMTP Password", ""),
{ name: "SSH / FTP Account", fields:[ new InputEntry("IMAP Server", ""),
new URLEntry( "Hostname", "" ), new PasswordEntry("IMAP Password", "")
new InputEntry( "Username", "" ), ]
new PasswordEntry( "Password", "" ) },
]}, {
{ name: "Credit Card", fields:[ name: "SSH / FTP Account", fields: [
new InputEntry( "Bank Name", "" ), new URLEntry("Hostname", ""),
new InputEntry( "Owner Name", "" ), new InputEntry("Username", "<default_username>"),
new InputEntry( "Card Number", "" ), new PasswordEntry("Password", "")
new InputEntry( "Valid Until", "" ), ]
new PasswordEntry( "CVV", "" ) },
]}, {
{ name: "Simple List", fields:[ name: "Credit Card", fields: [
new CheckboxEntry( "Option A", "" ), new InputEntry("Bank Name", ""),
new CheckboxEntry( "Option B", "" ), new InputEntry("Owner Name", "<default_full_name>"),
new CheckboxEntry( "Option C", "" ), new InputEntry("Card Number", ""),
new CheckboxEntry( "Option D", "" ), new InputEntry("Valid Until", ""),
new CheckboxEntry( "Option E", "" ), new PasswordEntry("CVV", "")
]} ]
},
{
name: "Simple List", fields: [
new CheckboxEntry("Option A", ""),
new CheckboxEntry("Option B", ""),
new CheckboxEntry("Option C", ""),
new CheckboxEntry("Option D", ""),
new CheckboxEntry("Option E", ""),
]
}
]; ];
/* /*
@@ -110,34 +120,47 @@ function escapeHtml(string) {
// Get a registered entry given its type. // Get a registered entry given its type.
function TypeProto(type) { function TypeProto(type) {
for( var i = 0; i < REGISTERED_TYPES.length; i++ ) { for (var i = 0; i < REGISTERED_TYPES.length; i++) {
var registered = REGISTERED_TYPES[i]; var registered = REGISTERED_TYPES[i];
if( registered.type == type ) { if (registered.type == type) {
return registered; return registered;
}
} }
}
return null; return null;
} }
// Clone a registered entry and make the instance id unique. // Clone a registered entry and make the instance id unique.
function TypeClone(e) { function TypeClone(e) {
var clone = $.extend( true, {}, e ); var clone = $.extend(true, {}, e);
clone.id += '_' + g_EntryCounter++; clone.id += '_' + g_EntryCounter++;
if (clone.value.indexOf('<default') == 0) {
var def_value_name = 'arc_' + clone.value.replaceAll('<', '').replaceAll('>', '');
// lookup default value from local storage
if (window.localStorage.hasOwnProperty(def_value_name)) {
clone.value = window.localStorage[def_value_name];
} else {
// no default value has been defined yet for this, fallback to empty clone
clone.value = '';
}
} else {
// create an empty clone
clone.value = ""; clone.value = "";
}
return clone; return clone;
} }
// Create an Entry derived object from the 'o' JSON object. // Create an Entry derived object from the 'o' JSON object.
function TypeFactory(o) { function TypeFactory(o) {
var proto = TypeProto(o.type); var proto = TypeProto(o.type);
var entry = TypeClone(proto); var entry = TypeClone(proto);
entry.Populate(o); entry.Populate(o);
return entry; return entry;
} }

View File

@@ -0,0 +1,53 @@
<div class="modal modal-full" id="settings_modal" role="dialog" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-full" role="document">
<div class="modal-content modal-content-full">
<div class="modal-body modal-body-full" id="settings_body">
<form id="settings_form">
<div class="form-group">
<h1>Defaults</h1>
<div style="clear:both"></div>
<small class="form-text text-muted" id="cleartext-warning">
You can optionally define default values to be used in secret templates.
</small>
<br />
<div class="form-group">
<h5 class="editable label label-default entry-title label-0">Login</h5>
<div style="clear:both"></div>
<div class="input-group mif">
<input class="form-control" data-entry-type="0" type="text" name="arc_default_login"
id="arc_default_login" value="">
</div>
</div>
<div class="form-group">
<h5 class="editable label label-default entry-title label-0">Username</h5>
<div style="clear:both"></div>
<div class="input-group mif">
<input class="form-control" data-entry-type="0" type="text" name="arc_default_username"
id="arc_default_username" value="">
</div>
</div>
<div class="form-group">
<h5 class="editable label label-default entry-title label-0">Full Name</h5>
<div style="clear:both"></div>
<div class="input-group mif">
<input class="form-control" data-entry-type="0" type="text" name="arc_default_full_name"
id="arc_default_full_name" value="">
</div>
</div>
<br />
<button type="submit" class="btn btn-secondary float-right" ng-click="doSaveSettings()"
id="saveSettingsButton">Save</button>
</div>
</form>
</div>
</div> <!-- content -->
</div> <!-- dialog -->
</div>