First commit
This commit is contained in:
60
app/frontend/src/views/SimpleKeyboard.vue
Normal file
60
app/frontend/src/views/SimpleKeyboard.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div :class="keyboardClass"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Keyboard from "simple-keyboard";
|
||||
import "simple-keyboard/build/css/index.css";
|
||||
|
||||
export default {
|
||||
name: "SimpleKeyboard",
|
||||
props: {
|
||||
keyboardClass: {
|
||||
default: "simple-keyboard",
|
||||
type: String
|
||||
},
|
||||
input: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
keyboard: null
|
||||
}),
|
||||
mounted() {
|
||||
this.keyboard = new Keyboard({
|
||||
onChange: this.onChange,
|
||||
onKeyPress: this.onKeyPress
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
onChange(input) {
|
||||
this.$emit("onChange", input);
|
||||
},
|
||||
onKeyPress(button) {
|
||||
this.$emit("onKeyPress", button);
|
||||
|
||||
/**
|
||||
* If you want to handle the shift and caps lock buttons
|
||||
*/
|
||||
if (button === "{shift}" || button === "{lock}") this.handleShift();
|
||||
},
|
||||
handleShift() {
|
||||
let currentLayout = this.keyboard.options.layoutName;
|
||||
let shiftToggle = currentLayout === "default" ? "shift" : "default";
|
||||
|
||||
this.keyboard.setOptions({
|
||||
layoutName: shiftToggle
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
input(input) {
|
||||
this.keyboard.setInput(input);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
70
app/frontend/src/views/analysis.vue
Normal file
70
app/frontend/src/views/analysis.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="center">
|
||||
<div v-if="question">
|
||||
<p>Do you want to analyze the captured communications?</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn" v-on:click="save_capture()">No, just save them</button> <button class="btn btn-primary" v-on:click="start_analysis()">Yes, let's do it</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="running">
|
||||
<img src="@/assets/loading.svg"/>
|
||||
<p class="legend" v-if="!long_waiting">Please wait during the analysis...</p>
|
||||
<p class="legend fade-in" v-if="long_waiting">Yes, it can take some time...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import router from '../router'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'analysis',
|
||||
data() {
|
||||
return {
|
||||
question: true,
|
||||
running: false,
|
||||
check_alerts: false,
|
||||
long_waiting: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
capture_token: String
|
||||
},
|
||||
methods: {
|
||||
start_analysis: function() {
|
||||
this.question = false
|
||||
this.running = true
|
||||
setTimeout(function () { this.long_waiting = true }.bind(this), 15000);
|
||||
axios.get(`/api/analysis/start/${this.capture_token}`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if(response.data.message == "Analysis started")
|
||||
this.check_alerts = setInterval(() => { this.get_alerts(); }, 500);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
get_alerts: function() {
|
||||
axios.get(`/api/analysis/report/${this.capture_token}`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if(response.data.message != "No report yet"){
|
||||
clearInterval(this.check_alerts);
|
||||
this.long_waiting = false;
|
||||
this.running = false;
|
||||
router.replace({ name: 'report', params: { alerts : response.data.alerts,
|
||||
device : response.data.device,
|
||||
capture_token : this.capture_token } });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
save_capture: function() {
|
||||
var capture_token = this.capture_token
|
||||
router.replace({ name: 'save-capture', params: { capture_token: capture_token } });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
100
app/frontend/src/views/capture.vue
Normal file
100
app/frontend/src/views/capture.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="capture-wrapper">
|
||||
<svg id="sparkline" stroke-width="3" :width="sparkwidth" :height="sparkheight" v-if="sparklines"></svg>
|
||||
<div class="center">
|
||||
<div class="footer">
|
||||
<h3 class="timer">{{timer_hours}}:{{timer_minutes}}:{{timer_seconds}}</h3>
|
||||
<p>Intercepting the communications of {{device_name}}.</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn" :class="[ loading ? 'loading' : 'btn-primary', ]" v-on:click="stop_capture()">Stop the capture</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import router from '../router'
|
||||
import sparkline from '@fnando/sparkline'
|
||||
|
||||
export default {
|
||||
name: 'capture',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
timer_hours: "00",
|
||||
timer_minutes: "00",
|
||||
timer_seconds: "00",
|
||||
loading: false,
|
||||
stats_interval: false,
|
||||
chrono_interval: false,
|
||||
sparklines: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
capture_token: String,
|
||||
device_name: String
|
||||
},
|
||||
methods: {
|
||||
set_chrono: function() {
|
||||
this.chrono_interval = setInterval(() => { this.chrono(); }, 10);
|
||||
},
|
||||
stop_capture: function() {
|
||||
this.loading = true
|
||||
axios.get(`/api/network/ap/stop`, { timeout: 30000 })
|
||||
axios.get(`/api/capture/stop`, { timeout: 30000 })
|
||||
.then(response => (this.handle_finish(response.data)))
|
||||
},
|
||||
get_stats: function() {
|
||||
axios.get(`/api/capture/stats`, { timeout: 30000 })
|
||||
.then(response => (this.handle_stats(response.data)))
|
||||
},
|
||||
handle_stats: function(data) {
|
||||
if (data.packets.length) sparkline(document.querySelector("#sparkline"), data.packets);
|
||||
},
|
||||
handle_finish: function(data) {
|
||||
clearInterval(this.chrono_interval);
|
||||
clearInterval(this.stats_interval);
|
||||
if (data.status) {
|
||||
this.loading = false
|
||||
var capture_token = this.capture_token
|
||||
router.replace({ name: 'analysis', params: { capture_token: capture_token } });
|
||||
}
|
||||
},
|
||||
chrono: function() {
|
||||
var time = Date.now() - this.capture_start
|
||||
this.timer_hours = Math.floor(time / (60 * 60 * 1000));
|
||||
this.timer_hours = (this.timer_hours < 10) ? "0" + this.timer_hours : this.timer_hours
|
||||
time = time % (60 * 60 * 1000);
|
||||
this.timer_minutes = Math.floor(time / (60 * 1000));
|
||||
this.timer_minutes = (this.timer_minutes < 10) ? "0" + this.timer_minutes : this.timer_minutes
|
||||
time = time % (60 * 1000);
|
||||
this.timer_seconds = Math.floor(time / 1000);
|
||||
this.timer_seconds = (this.timer_seconds < 10) ? "0" + this.timer_seconds : this.timer_seconds
|
||||
},
|
||||
setup_sparklines: function() {
|
||||
axios.get(`/api/misc/config`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if(response.data.sparklines){
|
||||
this.sparklines = true
|
||||
this.sparkwidth = window.screen.width + "px";
|
||||
this.sparkheight = Math.trunc(window.screen.height / 5) + "px";
|
||||
this.stats_interval = setInterval(() => { this.get_stats(); }, 500);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
// Get the config for the sparklines.
|
||||
this.setup_sparklines()
|
||||
|
||||
// Start the chrono and get the first stats.
|
||||
this.capture_start = Date.now()
|
||||
this.set_chrono();
|
||||
}
|
||||
}
|
||||
</script>
|
119
app/frontend/src/views/generate-ap.vue
Normal file
119
app/frontend/src/views/generate-ap.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="center">
|
||||
<div v-if="(error == false)">
|
||||
<div v-if="ssid_name">
|
||||
<div class="card apcard" v-on:click="generate_ap()">
|
||||
<div class="columns">
|
||||
<div class="column col-5">
|
||||
<center><img :src="ssid_qr" id="qrcode"></center>
|
||||
</div>
|
||||
<div class="divider-vert white-bg" data-content="OR"></div>
|
||||
<div class="column col-5"><br />
|
||||
<span class="light-grey">Network name: </span><br />
|
||||
<h4>{{ ssid_name }}</h4>
|
||||
<span class="light-grey">Network password: </span><br />
|
||||
<h4>{{ ssid_password }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br /><br /><br /><br /> <br /><br /><br /><br /><br /><br />
|
||||
<!-- Requite a CSS MEME for that shit :) -->
|
||||
<span class="legend">Tap the white frame to generate a new network.</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<img src="@/assets/loading.svg"/>
|
||||
<p class="legend">We generate an ephemeral network for you.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>
|
||||
<strong>Unfortunately, we got some issues.</strong>
|
||||
<br /><br />
|
||||
Please verify that you've two Wifi interfaces on your device<br />
|
||||
and restart it by clicking on the button below.<br />
|
||||
</p>
|
||||
<button class="btn" v-on:click="reboot()">Reboot the device</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import router from '../router'
|
||||
|
||||
export default {
|
||||
name: 'generate-ap',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
ssid_name: false,
|
||||
ssid_qr: false,
|
||||
ssid_password: false,
|
||||
capture_token: false,
|
||||
capture_start: false,
|
||||
interval: false,
|
||||
error: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generate_ap: function() {
|
||||
clearInterval(this.interval)
|
||||
this.ssid_name = false
|
||||
axios.get(`/api/network/ap/start`, { timeout: 30000 })
|
||||
.then(response => (this.show_ap(response.data)))
|
||||
},
|
||||
show_ap: function(data) {
|
||||
if (data.status) {
|
||||
this.ssid_name = data.ssid
|
||||
this.ssid_password = data.password
|
||||
this.ssid_qr = data.qrcode
|
||||
this.start_capture() // Start the capture before client connect.
|
||||
} else {
|
||||
this.error = true
|
||||
}
|
||||
},
|
||||
start_capture: function() {
|
||||
axios.get(`/api/capture/start`, { timeout: 30000 })
|
||||
.then(response => (this.get_capture_token(response.data)))
|
||||
},
|
||||
reboot: function() {
|
||||
axios.get(`/api/misc/reboot`, { timeout: 30000 })
|
||||
.then(response => { console.log(response)})
|
||||
},
|
||||
get_capture_token: function(data) {
|
||||
if (data.status) {
|
||||
this.capture_token = data.capture_token
|
||||
this.capture_start = Date.now()
|
||||
this.get_device()
|
||||
}
|
||||
},
|
||||
get_device: function() {
|
||||
this.interval = setInterval(() => {
|
||||
axios.get(`/api/device/get/${this.capture_token}`, { timeout: 30000 })
|
||||
.then(response => (this.check_device(response.data)))
|
||||
}, 500);
|
||||
},
|
||||
check_device: function(data) {
|
||||
if (data.status) {
|
||||
clearInterval(this.interval);
|
||||
var capture_token = this.capture_token
|
||||
var capture_start = this.capture_start
|
||||
var device_name = data.name
|
||||
router.replace({
|
||||
name: 'capture',
|
||||
params: {
|
||||
capture_token: capture_token,
|
||||
capture_start: capture_start,
|
||||
device_name: device_name
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.generate_ap();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
24
app/frontend/src/views/home.vue
Normal file
24
app/frontend/src/views/home.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="center">
|
||||
<h3 class="lobster">Welcome to TinyCheck.</h3>
|
||||
<p>We are going to help you to check your device.</p>
|
||||
<button class="btn btn-primary" v-on:click="next()">Let's start!</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import router from '../router'
|
||||
|
||||
export default {
|
||||
name: 'home',
|
||||
props: { saved_ssid: String, list_ssids: Array, internet: Boolean },
|
||||
methods: {
|
||||
next: function() {
|
||||
var saved_ssid = this.saved_ssid
|
||||
var list_ssids = this.list_ssids
|
||||
var internet = this.internet
|
||||
router.push({ name: 'wifi-select', params: { saved_ssid: saved_ssid, list_ssids: list_ssids, internet:internet } });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
115
app/frontend/src/views/report.vue
Normal file
115
app/frontend/src/views/report.vue
Normal file
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="results">
|
||||
<div v-if="alerts.high.length >= 1" class="high-wrapper">
|
||||
<div class="center">
|
||||
<h1 class="warning-title">You have {{ nb_translate(alerts.high.length) }} high alert,<br />your device seems to be compromised.</h1>
|
||||
<button class="btn btn-report-low-light" v-on:click="new_capture()">Start a new capture</button>
|
||||
<button class="btn btn-report-high" @click="show_report=true;results=false;">Show the full report</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="alerts.moderate.length >= 1" class="med-wrapper">
|
||||
<div class="center">
|
||||
<h1 class="warning-title">You have {{ nb_translate(alerts.moderate.length) }} moderate alerts,<br />your device might be compromised.</h1>
|
||||
<button class="btn btn-report-low-light" v-on:click="new_capture()">Start a new capture</button>
|
||||
<button class="btn btn-report-moderate" @click="show_report=true;results=false;">Show the full report</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="alerts.low.length >= 1" class="low-wrapper">
|
||||
<div class="center">
|
||||
<h1 class="warning-title">You have ony {{ nb_translate(alerts.moderate.low) }} low alerts,<br /> don't hesitate to check them.</h1>
|
||||
<button class="btn btn-report-low-light" v-on:click="new_capture()">Start a new capture</button>
|
||||
<button class="btn btn-report-low" @click="show_report=true;results=false;">Show the full report</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="none-wrapper">
|
||||
<div class="center">
|
||||
<h1 class="warning-title">Everything looks fine, zero alerts.</h1>
|
||||
<button class="btn btn-report-low-light" v-on:click="save_capture()">Save the capture</button>
|
||||
<button class="btn btn-report-low" v-on:click="new_capture()">Start a new capture</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="show_report" class="report-wrapper">
|
||||
<div class="device-ctx">
|
||||
<h3 style="margin: 0;">Report for {{device.name}}</h3>
|
||||
IP Address: {{device.ip_address}}<br />Mac Address: {{device.mac_address}}
|
||||
</div>
|
||||
<ul class="alerts">
|
||||
<li class="alert" v-for="alert in alerts.high" :key="alert.message">
|
||||
<span class="high-label">High</span><span class="alert-id">{{ alert.id }}</span>
|
||||
<div class="alert-body">
|
||||
<span class="title">{{ alert.title }}</span>
|
||||
<p class="description">{{ alert.description }}</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="alert" v-for="alert in alerts.moderate" :key="alert.message">
|
||||
<span class="moderate-label">Moderate</span><span class="alert-id">{{ alert.id }}</span>
|
||||
<div class="alert-body">
|
||||
<span class="title">{{ alert.title }}</span>
|
||||
<p class="description">{{ alert.description }}</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="alert" v-for="alert in alerts.low" :key="alert.message">
|
||||
<span class="low-label">Low</span><span class="alert-id">{{ alert.id }}</span>
|
||||
<div class="alert-body">
|
||||
<span class="title">{{ alert.title }}</span>
|
||||
<p class="description">{{ alert.description }}</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="columns" id="controls-analysis">
|
||||
<div class="column col-5">
|
||||
<button class="btn width-100" @click="$router.push('generate-ap')">Start a capture</button>
|
||||
</div>
|
||||
<div class="divider-vert column col-2" data-content="OR"></div>
|
||||
<div class="column col-5">
|
||||
<button class="btn btn btn-primary width-100" v-on:click="save_capture()">Save the report</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style>
|
||||
#app {
|
||||
overflow-y: visible;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import router from '../router'
|
||||
|
||||
export default {
|
||||
name: 'report',
|
||||
data() {
|
||||
return {
|
||||
results: true,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
device: Object,
|
||||
alerts: Array,
|
||||
capture_token: String
|
||||
},
|
||||
methods: {
|
||||
save_capture: function() {
|
||||
var capture_token = this.capture_token
|
||||
router.replace({ name: 'save-capture', params: { capture_token: capture_token } });
|
||||
},
|
||||
new_capture: function() {
|
||||
router.push({ name: 'generate-ap' })
|
||||
},
|
||||
nb_translate: function(x) {
|
||||
var nbs = ['zero','one','two','three','four', 'five','six','seven','eight','nine', 'ten', 'eleven']
|
||||
try {
|
||||
return nbs[x];
|
||||
} catch (error)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
200
app/frontend/src/views/save-capture.vue
Normal file
200
app/frontend/src/views/save-capture.vue
Normal file
@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<div class="center" v-if="save_usb && init">
|
||||
<div class="canvas-anim" :class="{'anim-connect': !saved && !usb}" v-on:click="new_capture()">
|
||||
<div class="icon-spinner" v-if="!saved && usb"></div>
|
||||
<div class="icon-success" v-if="saved"></div>
|
||||
<div class="icon-usb"></div>
|
||||
<div class="icon-usb-plug"></div>
|
||||
</div>
|
||||
<p class="legend" v-if="!saved && !usb"><br />Please connect a USB key to save your capture.</p>
|
||||
<p class="legend" v-if="!saved && usb"><br />We are saving your capture.</p>
|
||||
<p class="legend" v-if="saved"><br />You can tap the USB key to start a new capture.</p>
|
||||
</div>
|
||||
<div class="center" v-else-if="!save_usb && init">
|
||||
<div>
|
||||
<p class="legend">The capture download is going to start...<br /><br /><br /></p>
|
||||
<button class="btn btn-primary" v-on:click="new_capture()">Start another capture</button>
|
||||
<iframe :src="download_url" class="frame-download"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.canvas-anim {
|
||||
height: 120px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
width: 205px;
|
||||
|
||||
&.anim-connect {
|
||||
width: 300px;
|
||||
|
||||
.icon-usb {
|
||||
-webkit-animation: slide-right 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite alternate both;
|
||||
animation: slide-right 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite alternate both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-usb {
|
||||
background: url('../assets/icon_usb.svg') no-repeat 0 0;
|
||||
background-size: 200px auto;
|
||||
display: block;
|
||||
height: 120px;
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 0;
|
||||
width: 200px;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.icon-usb-plug {
|
||||
background: url('../assets/icon_plug_usb.svg') no-repeat 0 0;
|
||||
background-size: cover;
|
||||
display: block;
|
||||
height: 120px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -10px;
|
||||
width: 55px;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.icon-success {
|
||||
background: url('../assets/icon_success.svg') no-repeat 0 0;
|
||||
background-size: 80px auto;
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 120px;
|
||||
top: -25px;
|
||||
left: -40px;
|
||||
width: 80px;
|
||||
z-index: 10;
|
||||
-webkit-animation: scale-down-center 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: scale-down-center 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
|
||||
.icon-spinner {
|
||||
background: url('../assets/icon_spinner.svg') no-repeat 0 0;
|
||||
background-color: #f7f8f9;
|
||||
border-radius: 40px;
|
||||
display: block;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: -20px;
|
||||
width: 40px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@-webkit-keyframes slide-right {
|
||||
0% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateX(75px);
|
||||
transform: translateX(75px);
|
||||
}
|
||||
}
|
||||
@keyframes slide-right {
|
||||
0% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateX(75px);
|
||||
transform: translateX(75px);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes scale-down-center {
|
||||
0% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale(0.5);
|
||||
transform: scale(0.5);
|
||||
}
|
||||
}
|
||||
@keyframes scale-down-center {
|
||||
0% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale(0.5);
|
||||
transform: scale(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import router from '../router'
|
||||
|
||||
export default {
|
||||
name: 'save-capture',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
usb: false,
|
||||
saved: false,
|
||||
save_usb: false,
|
||||
init: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
capture_token: String
|
||||
},
|
||||
methods: {
|
||||
check_usb: function() {
|
||||
axios.get(`/api/save/usb-check`, { timeout: 30000 })
|
||||
.then(response => {
|
||||
if(response.data.status) {
|
||||
this.usb = true
|
||||
clearInterval(this.interval)
|
||||
this.save_capture()
|
||||
}
|
||||
})
|
||||
},
|
||||
save_capture: function() {
|
||||
var capture_token = this.capture_token
|
||||
axios.get(`/api/save/save-capture/${capture_token}/usb`, { timeout: 30000 })
|
||||
.then(response => {
|
||||
if(response.data.status){
|
||||
this.saved = true
|
||||
this.timeout = setTimeout(() => router.push('/'), 60000);
|
||||
}
|
||||
})
|
||||
},
|
||||
new_capture: function() {
|
||||
clearTimeout(this.timeout);
|
||||
router.push({ name: 'generate-ap' })
|
||||
},
|
||||
load_config: function() {
|
||||
axios.get(`/api/misc/config`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if(response.data.download_links){
|
||||
this.init = true
|
||||
this.save_usb = false
|
||||
this.download_url = `/api/save/save-capture/${this.capture_token}/url`
|
||||
} else {
|
||||
this.init = true
|
||||
this.save_usb = true
|
||||
this.interval = setInterval(() => { this.check_usb() }, 500);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.load_config()
|
||||
}
|
||||
}
|
||||
</script>
|
53
app/frontend/src/views/splash-screen.vue
Normal file
53
app/frontend/src/views/splash-screen.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="center">
|
||||
<img src="@/assets/logo.png" id="tinycheck-logo" />
|
||||
<div class="loading loading-lg loadingsplash"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import router from '../router'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'splash-screen',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
list_ssids: [],
|
||||
internet: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Check if the device is already connected to internet.
|
||||
internet_check: function() {
|
||||
axios.get(`/api/network/status`, { timeout: 10000 })
|
||||
.then(response => {
|
||||
if (response.data.internet) this.internet = true
|
||||
this.get_wifi_networks()
|
||||
})
|
||||
.catch(err => (console.log(err)))
|
||||
},
|
||||
// Get the WiFi networks around the box.
|
||||
get_wifi_networks: function() {
|
||||
axios.get(`/api/network/wifi/list`, { timeout: 10000 })
|
||||
.then(response => (this.append_ssids(response.data.networks)))
|
||||
.catch(err => (console.log(err)))
|
||||
},
|
||||
// Handle the get_wifi_networks answer and call goto_home.
|
||||
append_ssids: function(networks) {
|
||||
this.list_ssids = networks
|
||||
this.goto_home()
|
||||
},
|
||||
// Pass the list of ssids and the internet status as a prop to the home view.
|
||||
goto_home: function() {
|
||||
var list_ssids = this.list_ssids
|
||||
var internet = this.internet
|
||||
router.replace({ name: 'home', params: { list_ssids: list_ssids, internet: internet } });
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.internet_check();
|
||||
}
|
||||
}
|
||||
</script>
|
166
app/frontend/src/views/wifi-select.vue
Normal file
166
app/frontend/src/views/wifi-select.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div :class="[ keyboard == false ? 'center' : '' ]">
|
||||
<div v-if="keyboard == false">
|
||||
<div v-if="have_internet">
|
||||
<p>You seem to be already connected to a network.<br />Do you want to use the current connection?</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn" @click="have_internet = false">No, use another</button> <button class="btn" :class="[ connecting ? 'loading' : '', success ? 'btn-success' : 'btn-primary', ]" @click="$router.push({ name: 'generate-ap' })">Yes, use it.</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="enter_creds" class="wifi-login">
|
||||
<div class="form-group">
|
||||
<select class="form-select" id="ssid-select" v-model="ssid">
|
||||
<option value="" selected>Wifi name</option>
|
||||
<option v-for="ssid in ssids" v-bind:key="ssid.ssid">
|
||||
{{ ssid.ssid }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input class="form-input" type="password" id="password" v-model="password" placeholder="Wifi password" v-on:click="keyboard = (virtual_keyboard)? true : false">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn width-100" :class="[ connecting ? 'loading' : '', success ? 'btn-success' : 'btn-primary', ]" v-on:click="wifi_setup()">{{ btnval }}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn width-100" :class="[ refreshing ? 'loading' : '' ]" v-on:click="refresh_wifi_list()">Refresh networks list</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p><strong>You seem to not be connected to Internet.</strong><br />Please configure the Wi-Fi connection.</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn btn-primary" @click="enter_creds = true">Ok, let's do that.</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<input :value="input" class="keyboardinput" @input="onInputChange" placeholder="Tap on the virtual keyboard to start">
|
||||
<SimpleKeyboard @onChange="onChange" @onKeyPress="onKeyPress" :input="input" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import router from '../router'
|
||||
import SimpleKeyboard from "./SimpleKeyboard";
|
||||
|
||||
export default {
|
||||
name: 'wifi-select',
|
||||
components: {
|
||||
SimpleKeyboard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
connecting: false,
|
||||
error: false,
|
||||
success: false,
|
||||
btnval: "Connect to it.",
|
||||
ssid: "",
|
||||
selected_ssid: false,
|
||||
password: "",
|
||||
keyboard: false,
|
||||
input: "",
|
||||
ssids: [],
|
||||
have_internet: false,
|
||||
enter_creds: false,
|
||||
virtual_keyboard: false,
|
||||
refreshing: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
saved_ssid: String,
|
||||
list_ssids: Array,
|
||||
internet: Boolean
|
||||
},
|
||||
methods: {
|
||||
wifi_connect: function() {
|
||||
axios.get(`/api/network/wifi/connect`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if (response.data.status) {
|
||||
this.success = true
|
||||
this.connecting = false
|
||||
this.btnval = "Wifi connected!"
|
||||
setTimeout(() => router.push('generate-ap'), 1000);
|
||||
} else {
|
||||
this.btnval = "Wifi not connected. Please retry."
|
||||
this.connecting = false
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
},
|
||||
wifi_setup: function() {
|
||||
if (this.ssid.length && this.password.length >= 8 ){
|
||||
axios.post(`/api/network/wifi/setup`, { ssid: this.ssid, password: this.password }, { timeout: 60000 })
|
||||
.then(response => {
|
||||
if(response.data.status) {
|
||||
this.connecting = true
|
||||
this.wifi_connect()
|
||||
} else {
|
||||
console.log(response.data.message)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
},
|
||||
load_config: function() {
|
||||
axios.get(`/api/misc/config`, { timeout: 60000 })
|
||||
.then(response => {
|
||||
this.virtual_keyboard = response.data.virtual_keyboard
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
},
|
||||
onChange(input) {
|
||||
this.input = input
|
||||
this.password = this.input;
|
||||
},
|
||||
onKeyPress(button) {
|
||||
if (button == "{enter}")
|
||||
this.keyboard = false
|
||||
},
|
||||
onInputChange(input) {
|
||||
this.input = input.target.value;
|
||||
},
|
||||
append_ssids: function(networks) {
|
||||
this.ssids = networks
|
||||
},
|
||||
refresh_wifi_list: function(){
|
||||
this.refreshing = true
|
||||
axios.get(`/api/network/wifi/list`, { timeout: 10000 })
|
||||
.then(response => {
|
||||
this.refreshing = false
|
||||
this.append_ssids(response.data.networks)
|
||||
}).catch(error => {
|
||||
this.refreshing = false
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.load_config()
|
||||
|
||||
this.have_internet = (this.internet) ? true : false
|
||||
this.keyboard = false
|
||||
|
||||
if (typeof this.list_ssids == "object" && this.list_ssids.length != 0){
|
||||
this.ssids = this.list_ssids
|
||||
} else {
|
||||
this.refresh_wifi_list()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Reference in New Issue
Block a user