nano-tetra-modules/EvilPortal/module.html

568 lines
36 KiB
HTML

<div class="row" ng-controller="EvilPortalController">
<div class="col-md-3">
<!-- Controls Panel -->
<div class="panel panel-default">
<div class="panel-heading">
<a href="javascript:;" data-toggle="collapse" data-target="#collapseControls" class="text-muted"><h4
class="panel-title">Controls <img src="/img/throbber.gif" ng-show="throbber"/></h4></a>
</div>
<div id="collapseControls" class="panel-collapse collapse in">
<div class="panel-body">
<table style="width:100%">
<tr ng-repeat="control in controls" ng-show="control.visible">
<td style="padding-bottom: .5em;" class="text-muted">{{ control.title }}</td>
<!--<td style="text-align:right">{{ control.status }}</td>-->
<td style="text-align:right;padding-bottom: .5em;">
<button class="btn btn-default btn-sm" style="width:75px"
ng-click="handleControl(control)" ng-hide="control.throbber">{{ control.status
}}
</button>
<img src="/img/throbber.gif" ng-show="control.throbber"/>
</td>
</tr>
</table>
</div>
</div>
</div>
<!-- Messages Panel -->
<div class="panel panel-default">
<div class="panel-heading">
<a href="javascript:;" data-toggle="collapse" data-target="#collapseMessages" class="text-muted"><h4
class="panel-title">Evil Portal Messages</h4></a>
</div>
<div id="collapseMessages" class="panel-collapse collapse in">
<div class="panel-body">
<p ng-show="(messages.length == 0)" class="text-muted"><i>No Messages.</i></p>
<a ng-hide="(messages.length < 2)" ng-click="messages = []" class="pull-right" href="javascript:;">Clear
All</a>
<table style="width:100%" ng-hide="(messages.length == 0)">
<tr ng-repeat="message in messages">
<td>
<fieldset>
<legend><h5><b>{{ message.title }}</b> <a ng-click="dismissMessage($index)" href="javascript:;"
class="pull-right">Dismiss</a></h5></legend>
<p class="text-muted"><i>{{ message.msg }}</i></p>
</fieldset>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="panel-group" id="accordion">
<div class="col-md-9">
<!-- Library panel -->
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
data-target="#collapseLibrary" class="text-muted">Work Bench <b style="text-transform: capitalize"><i>{{ workshop.portal.title }}</i></b></a></h5>
</div>
<div id="collapseLibrary" class="panel-collapse collapse in">
<div class="panel-body">
<div class="input-group" ng-show="evilPortal.library">
<span class="input-group-btn">
<select class="form-control ng-pristine ng-valid ng-touched" style="width:80px" ng-model="newPortal.type">
<option value="basic">Basic</option>
<option value="targeted">Targeted</option>
</select>
</span>
<input type="text" class="form-control" placeholder="Portal Name" name="portalName" ng-model="newPortal.name">
<span class="input-group-btn">
<button ng-disabled="newPortal.name == ''" class="btn btn-default" type="button" ng-click="createNewPortal('internal')">Create New Portal</button>
<button ng-disabled="newPortal.name == ''" class="btn btn-default" type="button" ng-click="createNewPortal('sd')" ng-show="evilPortal.sdAvailable">Create On SD Card</button>
</span>
</div>
<hr ng-show="evilPortal.library"/>
<div ng-show="portals.length > 0 && evilPortal.library">
<div class="table-responsive">
<table class="table table-striped" align="center">
<thead>
<th>Portal Name</th>
<th>Portal Type</th>
<th>Location</th>
<th ng-show="evilPortal.sdAvailable">Move To</th>
<th>Logs</th>
<th>Activate</th>
<th>Delete</th>
</thead>
<tbody>
<tr ng-repeat="portal in portals">
<!-- Open portal work shop -->
<td><a href="javascript:;" ng-click="loadPortal(portal)" style="text-transform: capitalize"><b>{{ portal.title }}</b></a></td>
<!-- Portal type -->
<td class="text-muted" style="text-transform: capitalize">{{ portal.type }}</td>
<!-- What storage device the portal is on -->
<td class="text-muted" style="text-transform: capitalize">{{ portal.storage }}</td>
<!-- change storage -->
<td ng-show="evilPortal.sdAvailable">
<a ng-show="(portal.storage == 'internal') && !portal.active" href="javascript:;" ng-click="movePortal(portal, 'sd');">SD</a>
<a ng-show="(portal.storage == 'sd') && !portal.active" href="javascript:;" ng-click="movePortal(portal, 'internal');">Internal</a>
</td>
<td>
<a href="javascript:;" data-toggle="modal" data-target="#readLogsModal" ng-click="loadPortalLog(portal)">View</a>
</td>
<!-- activate/deactivate -->
<td>
<a ng-hide="portal.active" href="javascript:;" ng-click="activatePortal(portal)">Activate</a>
<a ng-show="portal.active" href="javascript:;" ng-click="deactivatePortal(portal)">Deactivate</a>
</td>
<!-- delete portal button -->
<td>
<a ng-hide="portal.active" data-toggle="modal" data-target="#deleteModal" ng-click="deletePortal(false, portal)">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div ng-hide="portals.length > 0 || !evilPortal.library">
<p class="text-muted text-center"><i>No Portals in Library to Display.</i></p>
</div>
<!-- Portal Editor -->
<div ng-hide="evilPortal.library">
<!-- Editor Buttons -->
<div class="row-fluid">
<span class="pull-left">
<button type="submit" class="btn btn-default btn-sm" ng-click="evilPortal.library = true; resetWorkshop()">Back</button>
</span>
<span class="pull-right">
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#readLogsModal" ng-click="loadPortalLog(workshop.portal)">View Log</button>
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#fileModal" ng-click="setupNewFile()">New File</button>
<!-- Holding off on toggle commands until a future release. Still need to think through how they should work. -->
<!--<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#commandEditorModal" ng-click="loadToggleCommands()">Toggle Commands</button>-->
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#ruleEditorModal" ng-show="workshop.portal.type == 'targeted'" ng-click="loadTargetedRules();">Target Rule Editor</button>
<button type="submit" class="btn btn-default btn-sm" ng-click="loadPortal(workshop.portal)">Refresh</button>
</span>
</div>
<br/>
<hr />
<!-- Portal Files -->
<div class="table-responsive">
<table class="table table-striped" align="center">
<thead>
<th>File Name</th>
<th>Size</th>
<th>Edit</th>
<th>Delete</th>
</thead>
<tbody>
<tr ng-repeat="file in workshop.dirContents">
<td>{{ file.name }}</td>
<td>{{ file.size }}</td>
<td><a href="javascript:;" ng-click="loadFileContent(file.path)" data-toggle="modal" data-target="#fileModal">Edit</a></td>
<td><a href="javascript:;" ng-click="workshop.deleteFile = file" data-toggle="modal" data-target="#deleteFileModal" ng-show="file.deletable">Delete</a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- EvilPortal White List Panel -->
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
data-target="#collapseWhiteList" class="text-muted"
ng-click="getList('whiteList')">White List</a></h5>
</div>
<div id="collapseWhiteList" class="panel-collapse collapse">
<div class="panel-body">
<p class="text-muted">
<i>This is a list of clients who are allowed to connect to the internet without ever viewing the captive portal.</i>
</p>
<p>
<textarea id="whiteListPool" class="form-control" rows="15" ng-mouseup="getClickedClient('whiteListPool', 'whiteListInput');" ng-model="whiteList.clients" readonly></textarea>
</p>
<div class="input-group">
<input type="text" class="form-control" placeholder="IP Address" name="whiteListInput"
ng-model="whiteList.toManipulate">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-click="addWhiteListClient()">Add</button>
<button class="btn btn-default" type="button" ng-click="removeClientFromList('whiteList')">Remove</button>
</span>
</div>
<br/>
<button class="btn btn-default btn-sm" type="button" ng-click="getList('whiteList')">Refresh</button>
</div>
</div>
</div>
<!-- EvilPortal Authorized Clients Panel -->
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
data-target="#collapseAuthorizedClients" class="text-muted"
ng-click="getList('accessList')">Authorized Clients</a></h5>
</div>
<div id="collapseAuthorizedClients" class="panel-collapse collapse">
<div class="panel-body">
<div ng-show="evilPortal.running">
<p class="text-muted">
<i>This is a list of clients who have been authorized through the captive portal.</i>
</p>
<p>
<textarea id='authorizedPool' class="form-control" rows="15" ng-mouseup="getClickedClient('authorizedPool', 'accessListInput');" ng-model="accessList.clients" readonly></textarea>
</p>
<div class="input-group">
<input type="text" class="form-control" placeholder="IP Address" name="accessListInput" ng-model="accessList.toManipulate">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-click="authorizeClient()">Authorize</button>
<button class="btn btn-default" type="button" ng-click="removeClientFromList('accessList')">Revoke</button>
</span>
</div>
<br />
<button class="btn btn-default btn-sm" type="button" ng-click="getList('accessList')">Refresh</button>
</div>
<div ng-hide="evilPortal.running">
<p class="text-muted text-center"><i>Evil Portal must be started first.</i></p>
</div>
</div>
</div>
</div>
<!-- Live Preview Panel -->
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
data-target="#collapsePreview" ng-click="refreshLivePreview()"
class="text-muted">Live Preview</a></h5>
</div>
<div id="collapsePreview" class="panel-collapse collapse">
<div class="panel-body">
<div ng-show="evilPortal.running">
<iframe src="http://172.16.42.1" style="width:100%;height:300px;border:none;"
id="livePreviewIframe"></iframe>
<button type="submit" ng-click="refreshLivePreview()" class="btn btn-default btn-sm">Refresh</button>
</div>
<div ng-hide="evilPortal.running">
<p class="text-muted text-center"><i>Evil Portal must be started first.</i></p>
</div>
</div>
</div>
</div>
<!-- Change Log Pannel -->
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title"><a href="javascript:;" data-toggle="collapse" data-parent="#accordion"
data-target="#collapseChangelog" class="text-muted">Evil Portal Info</a></h5>
</div>
<div id="collapseChangelog" class="panel-collapse collapse">
<div class="panel-body">
<fieldset>
<legend>Disclaimer</legend>
<p><b>Evil Portal and all of its components are intended for professional use only. No one associated with this project is an anyway liable for your actions.</b></p>
</fieldset>
<fieldset>
<legend>Help</legend>
<h5>Summary</h5>
<p>Evil Portal is a captive portal program that enables you to easily create a captive portal for whatever your needs are. There are two kinds of portals Basic and Targeted.
Basic portals are just a simple page that gets served to all clients. Targeted portals allow you to serve a unique page to different clients based on a given rule.</p>
<h5>Basic Portals</h5>
<p>A Basic Portal is a one-size serves all kind of portal. These portals are designed to be a single page that all clients will land on. This is the traditional way
that captive portals work and the way Evil Portal as been doing things from the beginning.</p>
<h5>Targeted Portals</h5>
<p>A Targeted Portal allows you to serve a different page on a per-client basis based on a condition. This can be something like their mac address, user-agent, etc...
Targeted Portals give you a whole new dynamic to what Evil Portal can do, if you want clients who are connected to the SSID "Coffee Shop" to see a "Coffee Shop" branded portal
while at the same time clients with Android phones seeing an Android branded portal then this is what you want.</p>
<h5>Useful Links</h5>
<a href="https://forums.hak5.org/index.php?/topic/37874-official-evilportal/">Hak5 Forum Thread</a>
<br />
<a href="https://github.com/frozenjava/EvilPortalNano">GitHub Project</a>
</fieldset>
<fieldset>
<legend>Change Log</legend>
<ul>
<li><b>3.1</b></li>
<ul>
<li class="text-muted">Added ability to write and view logs on a per-portal basis</li>
<li class="text-muted">Created method <i>writeLog($message)</i> that writes to the portal log file</li>
<li class="text-muted">Created method <i>notify($message)</i> that sends a notification to the web ui</li>
<li class="text-muted">Added ability to download files</li>
<li class="text-muted">Tab button in file editor will now insert four spaces</li>
<li class="text-muted">Revamped the file editor modal</li>
<li class="text-muted">Showing file sizes in the portal work bench</li>
<li class="text-muted">Various quality of life improvements</li>
</ul>
<li><b>3.0</b></li>
<ul>
<li class="text-muted">Added ability to route clients to different portals based upon some identifier [ssid, mac vendor, ip, etc...]</li>
<li class="text-muted">Updated the work bench so users can choose between targeted and non-targeted portals</li>
<li class="text-muted">Created easy-to-use interface for creating targeting rules</li>
<li class="text-muted">Created some consistency throughout the UI</li>
<li class="text-muted">Added ability to create portals on an SD card and move between SD and Internal storage easily</li>
<li class="text-muted">Made white listed and authorized clients IP addresses clickable like SSIDs in PineAP</li>
<li class="text-muted">Created helper functions getClientMac, getClientSSID, getClientHostName</li>
<li class="text-muted">Sending notification when a client goes through a portal.</li>
<li class="text-muted">Various quality of life improvements</li>
</ul>
</ul>
<ul>
<li><b>2.1</b></li>
<ul>
<li class="text-muted">Removed un-needed verbosity</li>
<li class="text-muted">Made tab key indent in the editor instead of change elements</li>
<li class="text-muted">Added confirmation dialogue box when deleting a portal</li>
<li class="text-muted">Created auto-start feature</li>
<li class="text-muted">Various other quality of life updates</li>
</ul>
</ul>
<ul>
<li><b>2.0</b></li>
<ul>
<li class="text-muted">Captive Portal is now purely iptables (because F***
NoDogSplash)
</li>
</ul>
</ul>
<ul>
<li><b>1.0</b></li>
<ul>
<li class="text-muted">Initial Pineapple Nano Release</li>
</ul>
</ul>
</fieldset>
</div>
</div>
</div>
</div>
</div>
<!--</div>-->
<!-- Edit file modal -->
<div id="fileModal" class="modal fade" role="dialog">
<script type="text/javascript">
// Thanks to sud0nick on forums.hak5.org for this snippet
$(document).delegate('#evilportalEditor', 'keydown', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
for (var i = 0; i < 4; i++) {
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var $this = $(this);
var value = $this.val();
// set textarea value to: text before caret + tab + text after caret
$this.val(value.substring(0, start)
+ " "
+ value.substring(end));
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
}
}
});
</script>
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
ng-click="workshop.editFile = {}">&times;</button>
<h4 class="modal-title" ng-show="!workshop.editFile.isNewFile">Editing File</h4>
<h4 class="modal-title" ng-show="workshop.editFile.isNewFile">Creating New File</h4>
</div>
<div class="modal-body">
<label class="control-label">File Name</label>
<input type="text" class="form-control" ng-model="workshop.editFile.name" placeholder="Notes.txt" ng-disabled="!workshop.editFile.isNewFile">
<br />
<label class="control-label pull-left">File Contents</label>
<a href="javascript:;" ng-click="workshop.editFile.content = null" class="pull-right">Clear</a>
<textarea class="form-control" rows="20" ng-model="workshop.editFile.content" placeholder="Write some text here" id="evilportalEditor"/>
<label class="control-label pull-right">File Size: {{ workshop.editFile.size }}</label>
<a href="javascript:;" class="pull-left" ng-click="download(workshop.editFile.path)">Download</a>
<br />
<!-- <script src="modules/EvilPortal/includes/js/acejs/ace.js" type="text/javascript" charset="utf-8"></script> -->
</div>
<div class="modal-footer">
<button type="button" ng-click="saveFileContent(workshop.editFile);" class="btn btn-success pull-right" data-dismiss="modal"
ng-disabled="workshop.editFile.content == null">Save</button>
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="workshop.editFile = {}">Cancel</button>
</div>
</div>
</div>
</div>
<!-- Read Logs Modal -->
<div id="readLogsModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content -->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" ng-click="activeLog = null;">&times;</button>
<h4 class="modal-title">Viewing <i><b>{{ activeLog.path }}</b></i></h4>
</div>
<div class="modal-body">
<a href="javascript:;" class="pull-left" ng-click="loadLog(activeLog.path)">Refresh</a>
<a href="javascript:;" class="pull-right" ng-click="clearLog()">Clear</a>
<textarea class="form-control" rows="20" ng-model="activeLog.contents" placeholder="Nothing to show." readonly/>
<label class="control-label pull-right">Log Size: {{ activeLog.size }}</label>
<a href="javascript:;" class="pull-left" ng-click="download(activeLog.path)">Download</a>
<br />
</div>
</div>
</div>
</div>
<!-- Delete Portal Modal -->
<div id="deleteModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" ng-click="portalToDelete = null; portalDeleteValidation = null">&times;</button>
<h4 class="modal-title">Delete Portal <i>{{ portalToDelete.title }}</i>?</h4>
</div>
<div class="modal-body">
<p>You are about to delete {{ portalToDelete.title }} on {{ portalToDelete.storage }} storage. Once you do this it can not be undone.</p>
<p><b>Type the name of the portal you are trying to delete to continue.</b></p>
<input type="text" class="form-control" placeholder="PortalName" name="portalName" ng-model="portalDeleteValidation">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="portalToDelete = null; portalDeleteValidation = null">Cancel</button>
<button type="button" class="btn btn-danger pull-right" data-dismiss="modal" ng-click="deletePortal(true, portalToDelete)" ng-disabled="portalDeleteValidation.toLowerCase() != portalToDelete.title.toLowerCase()">Delete</button>
</div>
</div>
</div>
</div>
<!-- Delete file Modal -->
<div id="deleteFileModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" ng-click="workshop.deleteFile = {}">&times;</button>
<h4 class="modal-title">Delete File <i><b>{{ workshop.deleteFile.name }}</b></i>?</h4>
</div>
<div class="modal-body">
<p>You are about to delete <b>{{ workshop.deleteFile.path }}</b>. Once you do this it can not be undone.</p>
<p><b>Are you absolutely sure you want to delete <i>{{ workshop.deleteFile.name }}</i>?</b></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="workshop.deleteFile = {}">Cancel</button>
<button type="button" class="btn btn-danger pull-right" data-dismiss="modal" ng-click="deleteFile()">Delete {{ workshop.deleteFile.name }}</button>
</div>
</div>
</div>
</div>
<!-- Rule Editor Modal -->
<div id="ruleEditorModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" ng-click="">&times;</button>
<h4 class="modal-title">Editing Rules for {{ workshop.portal.title }}</h4>
</div>
<div class="modal-body">
<div ng-repeat="(key, data) in workshop.concreteTargetedRules.rules">
<fieldset>
<legend style="text-transform: uppercase">{{ key }}</legend>
<div ng-repeat="(specifier, values) in data">
<h5 style="text-transform: capitalize">{{ specifier }} <a href="javascript:;" data-target="#" ng-click="newTargetedRule(key, specifier);">Add Rule</a></h5>
<div class="table-responsive" ng-hide="isObjectEmpty(workshop.workingTargetedRules.rules[key][specifier])">
<table class="table table-striped" align="center">
<thead>
<th>Rule Key</th>
<th>Destination</th>
<!--<th>Commit</th>-->
<th>Remove</th>
</thead>
<tbody>
<tr ng-repeat="(i, rules) in workshop.workingTargetedRules.rules[key][specifier]">
<td><input type="text" placeholder="Key Value" ng-model="rules.key"></td>
<td><input type="text" placeholder="Destination.php" ng-model="rules.destination"></td>
<!--<td><a href="javascript:;" data-target="#" ng-click="commitPortalRule(key, specifier, i, rules.key, rules.destination)">Commit</a></td>-->
<td><button ng-click="removeTargetedRule(key, specifier, i)" class="btn btn-sm btn-danger">Remove</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</fieldset>
<br />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal" ng-click="">Cancel</button>
<button type="button" class="btn btn-success pull-right" data-dismiss="modal" ng-click="saveTargetedRules()" >Save</button>
</div>
</div>
</div>
</div>
<!-- Toggled command editor -->
<div id="commandEditorModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Toggle Commands for {{ workshop.portal.title }}</h4>
</div>
<div class="modal-body">
<fieldset>
<legend>On Activation - <a ng-click="saveToggleCommands('enable')">Save</a></legend>
<div class="center-block">
<!-- For sake of getting EP 3.0 release, I'm not going to implement this just yet.
<span class="center-block">
<button type="submit" class="btn btn-link btn-sm">Enable PineAP</button>
<button type="submit" class="btn btn-link btn-sm">Enable Karma Associations</button>
<button type="submit" class="btn btn-link btn-sm">Enable Beacon Response</button>
</span>-->
</div>
<textarea style="width:100%;" rows="10" ng-model="workshop.onEnable"></textarea>
</fieldset>
<fieldset>
<legend>On Deactivation - <a ng-click="saveToggleCommands('disable')">Save</a></legend>
<div class="row-fluid">
<!-- For sake of getting EP 3.0 release, I'm not going to implement this just yet.
<span class="center-block">
<button type="submit" class="btn btn-link btn-sm">Disable PineAP</button>
<button type="submit" class="btn btn-link btn-sm">Disable Karma Associations</button>
<button type="submit" class="btn btn-link btn-sm">Disable Beacon Response</button>
</span>-->
</div>
<textarea style="width:100%;" rows="10" ng-model="workshop.onDisable"></textarea>
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success pull-right" data-dismiss="modal" ng-click="saveToggleCommands('all')">Save All</button>
</div>
</div>
</div>
</div>
</div>