mirror of https://github.com/statping/statping
checkin form fix, user/token route for auth
parent
aeaba54f82
commit
79b6e620bf
|
@ -7,6 +7,7 @@
|
||||||
- Modified SCSS/SASS files to be generated from 1, main.scss to main.css
|
- Modified SCSS/SASS files to be generated from 1, main.scss to main.css
|
||||||
- Modified index page to use /assets directory for assets, (main.css, style.css)
|
- Modified index page to use /assets directory for assets, (main.css, style.css)
|
||||||
- Modified index page to use CDN asset paths
|
- Modified index page to use CDN asset paths
|
||||||
|
- Fixed New Checkin form
|
||||||
|
|
||||||
# 0.90.61 (07-22-2020)
|
# 0.90.61 (07-22-2020)
|
||||||
- Modified sass layouts, organized and split up sections
|
- Modified sass layouts, organized and split up sections
|
||||||
|
|
|
@ -3275,6 +3275,8 @@
|
||||||
"pm.test(\"Check Login JWT Token\", function () {",
|
"pm.test(\"Check Login JWT Token\", function () {",
|
||||||
" var jsonData = pm.response.json();",
|
" var jsonData = pm.response.json();",
|
||||||
" pm.expect(jsonData).to.have.property('token');",
|
" pm.expect(jsonData).to.have.property('token');",
|
||||||
|
" pm.expect(jsonData).to.have.property('admin');",
|
||||||
|
" pm.globals.set(\"token\", jsonData.token);",
|
||||||
"});"
|
"});"
|
||||||
],
|
],
|
||||||
"type": "text/javascript"
|
"type": "text/javascript"
|
||||||
|
@ -3371,24 +3373,141 @@
|
||||||
"_postman_previewlanguage": "json",
|
"_postman_previewlanguage": "json",
|
||||||
"header": [
|
"header": [
|
||||||
{
|
{
|
||||||
"key": "Content-Length",
|
"key": "Content-Type",
|
||||||
"value": "174"
|
"value": "application/json"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "Set-Cookie",
|
||||||
|
"value": "statping_auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInNjb3BlcyI6ImFkbWluIiwiZXhwIjoxNTk2NzQzMDUzfQ.dQQGgUDhFEjCL2Gi-Seg0hBp_sqVsDn3cXB0GpSorJI; Path=/; Expires=Thu, 06 Aug 2020 19:44:13 GMT; Max-Age=259200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Date",
|
||||||
|
"value": "Mon, 03 Aug 2020 19:44:13 GMT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Content-Length",
|
||||||
|
"value": "197"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Connection",
|
||||||
|
"value": "close"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cookie": [],
|
||||||
|
"body": "{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInNjb3BlcyI6ImFkbWluIiwiZXhwIjoxNTk2NzQzMDUzfQ.dQQGgUDhFEjCL2Gi-Seg0hBp_sqVsDn3cXB0GpSorJI\",\n \"admin\": true\n}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Check User Token",
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"id": "560e439b-d588-4a2f-a8a6-a0607531d74c",
|
||||||
|
"exec": [
|
||||||
|
"pm.test(\"Response is ok\", function () {",
|
||||||
|
" pm.response.to.have.status(200);",
|
||||||
|
"});",
|
||||||
|
"",
|
||||||
|
"pm.test(\"View Token Response\", function () {",
|
||||||
|
" var jsonData = pm.response.json();",
|
||||||
|
" pm.expect(jsonData.username).to.eql(\"admin\");",
|
||||||
|
" pm.expect(jsonData.admin).to.eql(true);",
|
||||||
|
" pm.expect(jsonData.scopes).to.eql(\"admin\");",
|
||||||
|
"});"
|
||||||
|
],
|
||||||
|
"type": "text/javascript"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"request": {
|
||||||
|
"auth": {
|
||||||
|
"type": "bearer",
|
||||||
|
"bearer": [
|
||||||
|
{
|
||||||
|
"key": "token",
|
||||||
|
"value": "{{api_key}}",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "urlencoded",
|
||||||
|
"urlencoded": [
|
||||||
|
{
|
||||||
|
"key": "token",
|
||||||
|
"value": "{{token}}",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{endpoint}}/api/users/token",
|
||||||
|
"host": [
|
||||||
|
"{{endpoint}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"users",
|
||||||
|
"token"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Send your JWT token from login to this endpoint to return the JSON values."
|
||||||
|
},
|
||||||
|
"response": [
|
||||||
|
{
|
||||||
|
"name": "Check User Token",
|
||||||
|
"originalRequest": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "urlencoded",
|
||||||
|
"urlencoded": [
|
||||||
|
{
|
||||||
|
"key": "token",
|
||||||
|
"value": "{{token}}",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{endpoint}}/api/users/token",
|
||||||
|
"host": [
|
||||||
|
"{{endpoint}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"users",
|
||||||
|
"token"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "OK",
|
||||||
|
"code": 200,
|
||||||
|
"_postman_previewlanguage": "json",
|
||||||
|
"header": [
|
||||||
{
|
{
|
||||||
"key": "Content-Type",
|
"key": "Content-Type",
|
||||||
"value": "application/json"
|
"value": "application/json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "Date",
|
"key": "Date",
|
||||||
"value": "Sat, 02 May 2020 00:56:17 GMT"
|
"value": "Mon, 03 Aug 2020 19:47:23 GMT"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "Set-Cookie",
|
"key": "Content-Length",
|
||||||
"value": "statping_auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsImV4cCI6MTU4ODY0MDE3N30.tf399_LfAphSGlKMtgphg6qpPrn-_w92XfCrK5FwbZY; Expires=Tue, 05 May 2020 00:56:17 GMT"
|
"value": "68"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Connection",
|
||||||
|
"value": "close"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cookie": [],
|
"cookie": [],
|
||||||
"body": "{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsImV4cCI6MTU4ODY0MDE3N30.tf399_LfAphSGlKMtgphg6qpPrn-_w92XfCrK5FwbZY\",\n \"admin\": true\n}"
|
"body": "{\n \"username\": \"admin\",\n \"admin\": true,\n \"scopes\": \"admin\",\n \"exp\": 1596743053\n}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -235,6 +235,11 @@ class Api {
|
||||||
return axios.post('api/theme', data).then(response => (response.data))
|
return axios.post('api/theme', data).then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async check_token(token) {
|
||||||
|
const f = {token: token}
|
||||||
|
return axios.post('api/users/token', qs.stringify(f)).then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
async login(username, password) {
|
async login(username, password) {
|
||||||
const f = {username: username, password: password}
|
const f = {username: username, password: password}
|
||||||
return axios.post('api/login', qs.stringify(f)).then(response => (response.data))
|
return axios.post('api/login', qs.stringify(f)).then(response => (response.data))
|
||||||
|
|
|
@ -15,7 +15,7 @@ A:HOVER {
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-muted {
|
.text-muted {
|
||||||
color: darken($text-color, 30%) !important;
|
color: lighten($text-color, 30%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day-success {
|
.day-success {
|
||||||
|
|
|
@ -15,7 +15,7 @@ $navbar-background: #ffffff;
|
||||||
$input-background: #fdfdfd;
|
$input-background: #fdfdfd;
|
||||||
$input-color: #4e4e4e;
|
$input-color: #4e4e4e;
|
||||||
$input-border: 1px solid #c9c9c9;
|
$input-border: 1px solid #c9c9c9;
|
||||||
$day-success-background: #18ce08;
|
$day-success-background: #20ac13;
|
||||||
$day-error-background: #d50a0a;
|
$day-error-background: #d50a0a;
|
||||||
|
|
||||||
/* Status Container */
|
/* Status Container */
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
<button @click="deleteCheckin(checkin)" class="btn btn-sm small btn-danger float-right text-uppercase">Delete</button>
|
<button @click="deleteCheckin(checkin)" class="btn btn-sm small btn-danger float-right text-uppercase">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control" :value="`${core.domain}/checkin/${checkin.api_key}`" readonly>
|
<input type="text" class="form-control" :value="`${core.domain}/checkin/${checkin.api_key}`" readonly>
|
||||||
<div class="input-group-append copy-btn">
|
<div class="input-group-append copy-btn">
|
||||||
|
@ -137,6 +136,9 @@ export default {
|
||||||
},
|
},
|
||||||
last_record(checkin) {
|
last_record(checkin) {
|
||||||
const r = this.records(checkin)
|
const r = this.records(checkin)
|
||||||
|
if (r.length === 0) {
|
||||||
|
return {success: false}
|
||||||
|
}
|
||||||
return r[0]
|
return r[0]
|
||||||
},
|
},
|
||||||
fixInts() {
|
fixInts() {
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
<label for="checkin_interval" class="col-form-label">Interval (minutes)</label>
|
<label for="checkin_interval" class="col-form-label">Interval (minutes)</label>
|
||||||
<input v-model="checkin.interval" type="number" name="interval" class="form-control" id="checkin_interval" placeholder="1" min="1">
|
<input v-model="checkin.interval" type="number" name="interval" class="form-control" id="checkin_interval" placeholder="1" min="1">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-5">
|
|
||||||
<label for="grace_period" class="col-form-label">Grace Period</label>
|
|
||||||
<input v-model="checkin.grace" type="number" name="grace" class="form-control" id="grace_period" placeholder="10">
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-5">
|
<div class="col-12 col-md-5">
|
||||||
<label class="col-form-label"></label>
|
<label class="col-form-label"></label>
|
||||||
<button @click.prevent="saveCheckin" type="submit" id="submit" class="btn btn-success d-block mt-2">Save Checkin</button>
|
<button @click.prevent="saveCheckin" type="submit" id="submit" class="btn btn-success d-block mt-2">Save Checkin</button>
|
||||||
|
@ -54,7 +50,6 @@
|
||||||
checkin: {
|
checkin: {
|
||||||
name: "",
|
name: "",
|
||||||
interval: 60,
|
interval: 60,
|
||||||
grace: 60,
|
|
||||||
service_id: this.service.id
|
service_id: this.service.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,9 @@
|
||||||
No updates found, create a new Incident Update below.
|
No updates found, create a new Incident Update below.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition-group name="fade" tag="div">
|
<div v-for="update in updates.reverse()" :key="update.id">
|
||||||
<div v-for="update in updates.reverse()" :key="update.id">
|
<IncidentUpdate :update="update" :onUpdate="loadUpdates" :admin="true"/>
|
||||||
<IncidentUpdate :update="update" :onUpdate="loadUpdates" :admin="true"/>
|
</div>
|
||||||
</div>
|
|
||||||
</transition-group>
|
|
||||||
|
|
||||||
<form class="row" @submit.prevent="createIncidentUpdate">
|
<form class="row" @submit.prevent="createIncidentUpdate">
|
||||||
<div class="col-12 col-md-3 mb-3 mb-md-0">
|
<div class="col-12 col-md-3 mb-3 mb-md-0">
|
||||||
|
@ -51,7 +49,7 @@
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
updates: [],
|
updates: null,
|
||||||
incident_update: {
|
incident_update: {
|
||||||
incident: this.incident.id,
|
incident: this.incident.id,
|
||||||
message: "",
|
message: "",
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="username" class="col-sm-2 col-form-label">{{$t('username')}}</label>
|
<label for="username" class="col-sm-2 col-form-label">{{$t('username')}}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input @keyup="checkForm" type="text" v-model="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
<input @keyup="checkForm" type="text" v-model="username" autocomplete="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="password" class="col-sm-2 col-form-label">{{$t('password')}}</label>
|
<label for="password" class="col-sm-2 col-form-label">{{$t('password')}}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input @keyup="checkForm" type="password" v-model="password" name="password" class="form-control" id="password" placeholder="Password">
|
<input @keyup="checkForm" type="password" v-model="password" autocomplete="current-password" name="password" class="form-control" id="password" placeholder="Password">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Api from "../API";
|
import Api from "../API";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormLogin',
|
name: 'FormLogin',
|
||||||
|
@ -59,17 +60,20 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
auth: {},
|
auth: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
google_scope: "https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email",
|
google_scope: "https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email",
|
||||||
slack_scope: "identity.email,identity.basic"
|
slack_scope: "identity.email,identity.basic"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
mounted() {
|
||||||
|
this.$cookies.remove("statping_auth")
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
checkForm() {
|
checkForm() {
|
||||||
if (!this.username || !this.password) {
|
if (!this.username || !this.password) {
|
||||||
this.disabled = true
|
this.disabled = true
|
||||||
|
@ -84,9 +88,10 @@
|
||||||
if (auth.error) {
|
if (auth.error) {
|
||||||
this.error = true
|
this.error = true
|
||||||
} else if (auth.token) {
|
} else if (auth.token) {
|
||||||
// this.$cookies.set("statping_auth", auth.token)
|
this.$cookies.set("statping_auth", auth.token)
|
||||||
await this.$store.dispatch('loadAdmin')
|
await this.$store.dispatch('loadAdmin')
|
||||||
this.$store.commit('setAdmin', auth.admin)
|
this.$store.commit('setAdmin', auth.admin)
|
||||||
|
this.$store.commit('setLoggedIn', true)
|
||||||
this.$router.push('/dashboard')
|
this.$router.push('/dashboard')
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
<div v-if="notifier.method==='mobile'">
|
<div v-if="notifier.method==='mobile'">
|
||||||
<div class="form-group row mt-3">
|
<div class="form-group row mt-3">
|
||||||
<label for="domain" class="col-sm-4 col-form-label">Statping Domain</label>
|
<label for="statping_domain" class="col-sm-4 col-form-label">Statping Domain</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input v-bind:value="$store.getters.core.domain" type="text" class="form-control" id="domain" readonly>
|
<input v-bind:value="$store.getters.core.domain" type="text" class="form-control" id="statping_domain" readonly>
|
||||||
<div class="input-group-append copy-btn">
|
<div class="input-group-append copy-btn">
|
||||||
<button @click.prevent="copy($store.getters.core.domain)" class="btn btn-outline-secondary" type="button">Copy</button>
|
<button @click.prevent="copy($store.getters.core.domain)" class="btn btn-outline-secondary" type="button">Copy</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -106,10 +106,6 @@ export default Vue.mixin({
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return this.$store.state.admin
|
return this.$store.state.admin
|
||||||
},
|
},
|
||||||
loggedIn() {
|
|
||||||
const core = this.$store.getters.core
|
|
||||||
return core.logged_in === true
|
|
||||||
},
|
|
||||||
iconName(name) {
|
iconName(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "fas fa-terminal":
|
case "fas fa-terminal":
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Api from "@/API";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
const Group = () => import('@/components/Index/Group')
|
const Group = () => import('@/components/Index/Group')
|
||||||
const Header = () => import('@/components/Index/Header')
|
const Header = () => import('@/components/Index/Header')
|
||||||
const MessageBlock = () => import('@/components/Index/MessageBlock')
|
const MessageBlock = () => import('@/components/Index/MessageBlock')
|
||||||
|
@ -44,10 +47,10 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
IncidentsBlock,
|
IncidentsBlock,
|
||||||
GroupServiceFailures,
|
GroupServiceFailures,
|
||||||
ServiceBlock,
|
ServiceBlock,
|
||||||
MessageBlock,
|
MessageBlock,
|
||||||
Group,
|
Group,
|
||||||
Header
|
Header
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -67,14 +70,24 @@ export default {
|
||||||
services_no_group() {
|
services_no_group() {
|
||||||
return this.$store.getters.servicesNoGroup
|
return this.$store.getters.servicesNoGroup
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async created() {
|
|
||||||
this.logged_in = this.loggedIn()
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async checkLogin() {
|
||||||
|
const token = this.$cookies.get('statping_auth')
|
||||||
|
if (!token) {
|
||||||
|
this.$store.commit('setLoggedIn', false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const jwt = await Api.check_token(token)
|
||||||
|
this.$store.commit('setAdmin', jwt.admin)
|
||||||
|
if (jwt.username) {
|
||||||
|
this.$store.commit('setLoggedIn', true)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
inRange(message) {
|
inRange(message) {
|
||||||
return this.isBetween(this.now(), message.start_on, message.start_on === message.end_on ? this.maxDate().toISOString() : message.end_on)
|
return this.isBetween(this.now(), message.start_on, message.start_on === message.end_on ? this.maxDate().toISOString() : message.end_on)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ const NotFound = () => import('@/pages/NotFound')
|
||||||
|
|
||||||
import VueRouter from "vue-router";
|
import VueRouter from "vue-router";
|
||||||
import Api from "./API";
|
import Api from "./API";
|
||||||
|
import store from "./store"
|
||||||
|
|
||||||
const Loading = {
|
const Loading = {
|
||||||
template: '<div class="jumbotron">LOADING</div>'
|
template: '<div class="jumbotron">LOADING</div>'
|
||||||
|
@ -26,7 +27,10 @@ const routes = [
|
||||||
{
|
{
|
||||||
path: '/setup',
|
path: '/setup',
|
||||||
name: 'Setup',
|
name: 'Setup',
|
||||||
component: Setup
|
component: Setup,
|
||||||
|
meta: {
|
||||||
|
title: 'Statping Setup',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
@ -37,14 +41,37 @@ const routes = [
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
component: Dashboard,
|
component: Dashboard,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Dashboard',
|
||||||
},
|
},
|
||||||
beforeEnter: async (to, from, next) => {
|
beforeEnter: async (to, from, next) => {
|
||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
let tk = await Api.token()
|
if (to.path !== '/login') {
|
||||||
if (to.path !== '/login' && !tk) {
|
if(store.getters.loggedIn) {
|
||||||
next('/login')
|
next()
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
const token = $cookies.get('statping_auth')
|
||||||
|
if (!token) {
|
||||||
|
next('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const jwt = await Api.check_token(token)
|
||||||
|
store.commit('setAdmin', jwt.admin)
|
||||||
|
if (jwt.admin) {
|
||||||
|
store.commit('setLoggedIn', true)
|
||||||
|
store.commit('setUser', true)
|
||||||
|
} else {
|
||||||
|
store.commit('setLoggedIn', false)
|
||||||
|
next('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
next('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,81 +82,96 @@ const routes = [
|
||||||
path: '',
|
path: '',
|
||||||
component: DashboardIndex,
|
component: DashboardIndex,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Dashboard',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'users',
|
path: 'users',
|
||||||
component: DashboardUsers,
|
component: DashboardUsers,
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Users',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'services',
|
path: 'services',
|
||||||
component: DashboardServices,
|
component: DashboardServices,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Services',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'create_service',
|
path: 'create_service',
|
||||||
component: EditService,
|
component: EditService,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Create Service',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'edit_service/:id',
|
path: 'edit_service/:id',
|
||||||
component: EditService,
|
component: EditService,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Edit Service',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'service/:id/incidents',
|
path: 'service/:id/incidents',
|
||||||
component: Incidents,
|
component: Incidents,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Incidents',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'service/:id/checkins',
|
path: 'service/:id/checkins',
|
||||||
component: Checkins,
|
component: Checkins,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Checkins',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'service/:id/failures',
|
path: 'service/:id/failures',
|
||||||
component: Failures,
|
component: Failures,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Service Failures',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'messages',
|
path: 'messages',
|
||||||
component: DashboardMessages,
|
component: DashboardMessages,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Messages',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
component: Settings,
|
component: Settings,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Settings',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'logs',
|
path: 'logs',
|
||||||
component: Logs,
|
component: Logs,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Logs',
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
path: 'help',
|
path: 'help',
|
||||||
component: Logs,
|
component: Logs,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
title: 'Statping - Help',
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
component: Login
|
component: Login,
|
||||||
|
meta: {
|
||||||
|
title: 'Statping - Login',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ path: '/logout', redirect: '/' },
|
{ path: '/logout', redirect: '/' },
|
||||||
{
|
{
|
||||||
|
@ -157,23 +199,23 @@ const router = new VueRouter({
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
let CheckAuth = (to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
const nearestWithTitle = to.matched.slice().reverse().find(r => r.meta && r.meta.title);
|
||||||
let item = this.$cookies.get("statping_auth")
|
const nearestWithMeta = to.matched.slice().reverse().find(r => r.meta && r.meta.metaTags);
|
||||||
window.console.log(item)
|
const previousNearestWithMeta = from.matched.slice().reverse().find(r => r.meta && r.meta.metaTags);
|
||||||
if (to.path !== '/login' && !item) {
|
if(nearestWithTitle) document.title = nearestWithTitle.meta.title;
|
||||||
next('/login')
|
Array.from(document.querySelectorAll('[data-vue-router-controlled]')).map(el => el.parentNode.removeChild(el));
|
||||||
return
|
if(!nearestWithMeta) return next();
|
||||||
}
|
nearestWithMeta.meta.metaTags.map(tagDef => {
|
||||||
const auth = JSON.parse(item)
|
const tag = document.createElement('meta');
|
||||||
if (!auth.token) {
|
Object.keys(tagDef).forEach(key => {
|
||||||
next('/login')
|
tag.setAttribute(key, tagDef[key]);
|
||||||
return
|
});
|
||||||
}
|
tag.setAttribute('data-vue-router-controlled', '');
|
||||||
next()
|
return tag;
|
||||||
} else {
|
})
|
||||||
next()
|
.forEach(tag => document.head.appendChild(tag));
|
||||||
}
|
next();
|
||||||
}
|
});
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -30,7 +30,8 @@ export default new Vuex.Store({
|
||||||
notifiers: [],
|
notifiers: [],
|
||||||
checkins: [],
|
checkins: [],
|
||||||
admin: false,
|
admin: false,
|
||||||
user: false
|
user: false,
|
||||||
|
loggedIn: false
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
hasAllData: state => state.hasAllData,
|
hasAllData: state => state.hasAllData,
|
||||||
|
@ -46,6 +47,7 @@ export default new Vuex.Store({
|
||||||
users: state => state.users,
|
users: state => state.users,
|
||||||
notifiers: state => state.notifiers,
|
notifiers: state => state.notifiers,
|
||||||
checkins: state => state.checkins,
|
checkins: state => state.checkins,
|
||||||
|
loggedIn: state => state.loggedIn,
|
||||||
|
|
||||||
isAdmin: state => state.admin,
|
isAdmin: state => state.admin,
|
||||||
isUser: state => state.user,
|
isUser: state => state.user,
|
||||||
|
@ -131,6 +133,9 @@ export default new Vuex.Store({
|
||||||
setAdmin (state, admin) {
|
setAdmin (state, admin) {
|
||||||
state.admin = admin
|
state.admin = admin
|
||||||
},
|
},
|
||||||
|
setLoggedIn (state, loggedIn) {
|
||||||
|
state.loggedIn = loggedIn
|
||||||
|
},
|
||||||
setUser (state, user) {
|
setUser (state, user) {
|
||||||
state.user = user
|
state.user = user
|
||||||
},
|
},
|
||||||
|
|
|
@ -51,17 +51,9 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
|
||||||
return jwtClaim, tokenString
|
return jwtClaim, tokenString
|
||||||
}
|
}
|
||||||
|
|
||||||
func getJwtToken(r *http.Request) (JwtClaim, error) {
|
func parseToken(token string) (JwtClaim, error) {
|
||||||
c, err := r.Cookie(cookieName)
|
|
||||||
if err != nil {
|
|
||||||
if err == http.ErrNoCookie {
|
|
||||||
return JwtClaim{}, err
|
|
||||||
}
|
|
||||||
return JwtClaim{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var claims JwtClaim
|
var claims JwtClaim
|
||||||
tkn, err := jwt.ParseWithClaims(c.Value, &claims, func(token *jwt.Token) (interface{}, error) {
|
tkn, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||||
return jwtKey, nil
|
return jwtKey, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -74,5 +66,16 @@ func getJwtToken(r *http.Request) (JwtClaim, error) {
|
||||||
if !tkn.Valid {
|
if !tkn.Valid {
|
||||||
return claims, errors.New("token is not valid")
|
return claims, errors.New("token is not valid")
|
||||||
}
|
}
|
||||||
return claims, err
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getJwtToken(r *http.Request) (JwtClaim, error) {
|
||||||
|
c, err := r.Cookie(cookieName)
|
||||||
|
if err != nil {
|
||||||
|
if err == http.ErrNoCookie {
|
||||||
|
return JwtClaim{}, err
|
||||||
|
}
|
||||||
|
return JwtClaim{}, err
|
||||||
|
}
|
||||||
|
return parseToken(c.Value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ func Router() *mux.Router {
|
||||||
// API USER Routes
|
// API USER Routes
|
||||||
api.Handle("/api/users", authenticated(apiAllUsersHandler, false)).Methods("GET")
|
api.Handle("/api/users", authenticated(apiAllUsersHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/users", authenticated(apiCreateUsersHandler, false)).Methods("POST")
|
api.Handle("/api/users", authenticated(apiCreateUsersHandler, false)).Methods("POST")
|
||||||
|
api.Handle("/api/users/token", http.HandlerFunc(apiCheckUserTokenHandler)).Methods("POST")
|
||||||
api.Handle("/api/users/{id}", authenticated(apiUserHandler, false)).Methods("GET")
|
api.Handle("/api/users/{id}", authenticated(apiUserHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/users/{id}", authenticated(apiUserUpdateHandler, false)).Methods("POST")
|
api.Handle("/api/users/{id}", authenticated(apiUserUpdateHandler, false)).Methods("POST")
|
||||||
api.Handle("/api/users/{id}", authenticated(apiUserDeleteHandler, false)).Methods("DELETE")
|
api.Handle("/api/users/{id}", authenticated(apiUserDeleteHandler, false)).Methods("DELETE")
|
||||||
|
|
|
@ -80,6 +80,23 @@ func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
returnJson(allUsers, w, r)
|
returnJson(allUsers, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiCheckUserTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.ParseForm()
|
||||||
|
token := r.PostForm.Get("token")
|
||||||
|
if token == "" {
|
||||||
|
sendErrorJson(errors.New("missing token parameter"), w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claim, err := parseToken(token)
|
||||||
|
if err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
returnJson(claim, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
|
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var user *users.User
|
var user *users.User
|
||||||
err := DecodeJSON(r, &user)
|
err := DecodeJSON(r, &user)
|
||||||
|
|
|
@ -19,11 +19,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMobileNotifier(t *testing.T) {
|
func TestMobileNotifier(t *testing.T) {
|
||||||
|
t.SkipNow()
|
||||||
err := utils.InitLogs()
|
err := utils.InitLogs()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
t.SkipNow()
|
|
||||||
|
|
||||||
mobileToken = utils.Params.GetString("MOBILE_TOKEN")
|
mobileToken = utils.Params.GetString("MOBILE_TOKEN")
|
||||||
if mobileToken == "" {
|
if mobileToken == "" {
|
||||||
|
|
Loading…
Reference in New Issue