mirror of https://github.com/statping/statping
fixed authentication via cookies, oauth login,
parent
2aa3bee623
commit
42e1b0216a
|
@ -33,6 +33,7 @@
|
||||||
"vue-apexcharts": "^1.5.2",
|
"vue-apexcharts": "^1.5.2",
|
||||||
"vue-clipboard2": "^0.3.1",
|
"vue-clipboard2": "^0.3.1",
|
||||||
"vue-codemirror": "^4.0.6",
|
"vue-codemirror": "^4.0.6",
|
||||||
|
"vue-cookies": "^1.7.0",
|
||||||
"vue-flatpickr-component": "^8.1.5",
|
"vue-flatpickr-component": "^8.1.5",
|
||||||
"vue-github-button": "^1.1.2",
|
"vue-github-button": "^1.1.2",
|
||||||
"vue-moment": "^4.1.0",
|
"vue-moment": "^4.1.0",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as Sentry from "@sentry/browser";
|
||||||
import * as Integrations from "@sentry/integrations";
|
import * as Integrations from "@sentry/integrations";
|
||||||
const qs = require('querystring');
|
const qs = require('querystring');
|
||||||
|
|
||||||
const tokenKey = "statping_user";
|
const tokenKey = "statping_auth";
|
||||||
const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping.com/3"
|
const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping.com/3"
|
||||||
|
|
||||||
class Api {
|
class Api {
|
||||||
|
@ -29,6 +29,10 @@ class Api {
|
||||||
return axios.post('api/core', obj).then(response => (response.data))
|
return axios.post('api/core', obj).then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async oauth_save(obj) {
|
||||||
|
return axios.post('api/oauth', obj).then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
async setup_save(data) {
|
async setup_save(data) {
|
||||||
return axios.post('api/setup', qs.stringify(data)).then(response => (response.data))
|
return axios.post('api/setup', qs.stringify(data)).then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
@ -228,19 +232,11 @@ class Api {
|
||||||
|
|
||||||
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))
|
return axios.post('api/login', qs.stringify(f)).then(response => (response.data))
|
||||||
.then(response => (response.data))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async logout() {
|
async logout() {
|
||||||
await axios.get('api/logout').then(response => (response.data))
|
return axios.get('api/logout').then(response => (response.data))
|
||||||
return localStorage.removeItem(tokenKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
saveToken(username, token, admin) {
|
|
||||||
const user = {username: username, token: token, admin: admin}
|
|
||||||
localStorage.setItem(tokenKey, JSON.stringify(user));
|
|
||||||
return user
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async scss_base() {
|
async scss_base() {
|
||||||
|
@ -255,17 +251,17 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
token() {
|
token() {
|
||||||
const tk = localStorage.getItem(tokenKey)
|
const tk = $cookies.get(tokenKey)
|
||||||
if (!tk) {
|
if (!tk) {
|
||||||
return {};
|
return {admin: false};
|
||||||
}
|
}
|
||||||
return JSON.parse(tk);
|
return tk;
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken() {
|
authToken() {
|
||||||
let user = JSON.parse(localStorage.getItem(tokenKey));
|
const tk = $cookies.get(tokenKey)
|
||||||
if (user && user.token) {
|
if (tk.token) {
|
||||||
return {'Authorization': 'Bearer ' + user.token};
|
return {'Authorization': 'Bearer ' + tk.token};
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,22 +32,19 @@
|
||||||
this.$router.push('/setup')
|
this.$router.push('/setup')
|
||||||
}
|
}
|
||||||
if (this.$route.path !== '/setup') {
|
if (this.$route.path !== '/setup') {
|
||||||
if (this.core.logged_in) {
|
if (this.$store.state.admin) {
|
||||||
await this.$store.dispatch('loadAdmin')
|
await this.$store.dispatch('loadAdmin')
|
||||||
} else {
|
} else {
|
||||||
await this.$store.dispatch('loadRequired')
|
await this.$store.dispatch('loadRequired')
|
||||||
}
|
}
|
||||||
this.loaded = true
|
this.loaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
if (this.$route.path !== '/setup') {
|
if (this.$route.path !== '/setup') {
|
||||||
const tk = localStorage.getItem("statping_user")
|
if (this.$store.state.admin) {
|
||||||
if (this.core.logged_in) {
|
|
||||||
this.logged_in = true
|
this.logged_in = true
|
||||||
await this.$store.dispatch('loadAdmin')
|
// await this.$store.dispatch('loadAdmin')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="navbar-text">
|
<span class="navbar-text">
|
||||||
<a href="#" class="nav-link" v-on:click="logout">Logout</a>
|
<a href="#" class="nav-link" @click.prevent="logout">Logout</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Api from "../../API"
|
import Api from "../../API"
|
||||||
|
import Vue from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TopNav',
|
name: 'TopNav',
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
this.$store.commit('setHasAllData', false)
|
this.$store.commit('setHasAllData', false)
|
||||||
this.$store.commit('setToken', null)
|
this.$store.commit('setToken', null)
|
||||||
this.$store.commit('setAdmin', false)
|
this.$store.commit('setAdmin', false)
|
||||||
|
this.$cookies.remove("statping_auth")
|
||||||
await this.$router.push('/logout')
|
await this.$router.push('/logout')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<a href="https://github.com/statping/statping" target="_blank">
|
<a href="https://github.com/statping/statping" target="_blank">
|
||||||
Statping {{core.version}} made with <font-awesome-icon icon="heart"/>
|
Statping {{core.version}} made with <font-awesome-icon icon="heart"/>
|
||||||
</a> |
|
</a> |
|
||||||
<router-link :to="core.logged_in ? '/dashboard' : '/login'">Dashboard</router-link>
|
<router-link :to="$store.state.admin ? '/dashboard' : '/login'">Dashboard</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="footer text-center mb-4 p-2" v-html="core.footer"></div>
|
<div v-else class="footer text-center mb-4 p-2" v-html="core.footer"></div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -25,16 +25,16 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a v-if="oauth.gh_client_id" :href="GHlogin()" class="btn btn-block">
|
<a v-if="oauth.gh_client_id" @click.prevent="GHlogin" href="#" class="btn btn-block btn-outline-dark">
|
||||||
Github Login
|
<font-awesome-icon :icon="['fab', 'github']" /> Login with Github
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a v-if="oauth.slack_client_id" :href="Slacklogin()" class="btn btn-block">
|
<a v-if="oauth.slack_client_id" @click.prevent="Slacklogin" href="#" class="btn btn-block btn-outline-dark">
|
||||||
Slack Login
|
<font-awesome-icon :icon="['fab', 'slack']" /> Login with Slack
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a v-if="oauth.google_client_id" :href="Googlelogin()" class="btn btn-block">
|
<a v-if="oauth.google_client_id" @click.prevent="Googlelogin" href="#" class="btn btn-block btn-outline-dark">
|
||||||
Google Login
|
<font-awesome-icon :icon="['fab', 'google']" /> Login with Google
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +80,8 @@
|
||||||
if (auth.error) {
|
if (auth.error) {
|
||||||
this.error = true
|
this.error = true
|
||||||
} else if (auth.token) {
|
} else if (auth.token) {
|
||||||
this.auth = Api.saveToken(this.username, auth.token, auth.admin)
|
const u = {username: this.username, admin: auth.admin, token: auth.token}
|
||||||
|
this.$cookies.set("statping_auth", JSON.stringify(u))
|
||||||
this.$store.dispatch('loadAdmin')
|
this.$store.dispatch('loadAdmin')
|
||||||
this.$store.commit('setAdmin', auth.admin)
|
this.$store.commit('setAdmin', auth.admin)
|
||||||
this.$router.push('/dashboard')
|
this.$router.push('/dashboard')
|
||||||
|
@ -88,13 +89,13 @@
|
||||||
this.loading = false
|
this.loading = false
|
||||||
},
|
},
|
||||||
GHlogin() {
|
GHlogin() {
|
||||||
return `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.core.domain}/api/oauth/github&scope=user,repo`
|
window.location = `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.core.domain}/oauth/github&scope=user,repo`
|
||||||
},
|
},
|
||||||
Slacklogin() {
|
Slacklogin() {
|
||||||
return `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.core.domain}/api/oauth/slack&scope=users.profile:read,users:read.email`
|
window.location = `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.core.domain}/oauth/slack&scope=identity.basic`
|
||||||
},
|
},
|
||||||
Googlelogin() {
|
Googlelogin() {
|
||||||
return `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/api/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email`
|
window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
core() {
|
core() {
|
||||||
return this.$store.getters.core
|
return this.$store.getters.core
|
||||||
},
|
},
|
||||||
oauth() {
|
auth() {
|
||||||
return this.$store.getters.oauth
|
return this.$store.getters.oauth
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -171,10 +171,22 @@
|
||||||
google_enabled: false,
|
google_enabled: false,
|
||||||
slack_enabled: false,
|
slack_enabled: false,
|
||||||
github_enabled: false,
|
github_enabled: false,
|
||||||
local_enabled: false
|
local_enabled: false,
|
||||||
|
oauth: {
|
||||||
|
gh_client_id: "",
|
||||||
|
gh_client_secret: "",
|
||||||
|
google_client_id: "",
|
||||||
|
google_client_secret: "",
|
||||||
|
oauth_domains: "",
|
||||||
|
oauth_providers: "",
|
||||||
|
slack_client_id: "",
|
||||||
|
slack_client_secret: "",
|
||||||
|
slack_team: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.oauth = this.auth
|
||||||
this.local_enabled = this.has('local')
|
this.local_enabled = this.has('local')
|
||||||
this.github_enabled = this.has('github')
|
this.github_enabled = this.has('github')
|
||||||
this.google_enabled = this.has('google')
|
this.google_enabled = this.has('google')
|
||||||
|
@ -207,10 +219,9 @@
|
||||||
let c = this.core
|
let c = this.core
|
||||||
c.oauth = this.oauth
|
c.oauth = this.oauth
|
||||||
c.oauth.oauth_providers = this.providers()
|
c.oauth.oauth_providers = this.providers()
|
||||||
await Api.core_save(c)
|
await Api.oauth_save(c)
|
||||||
const core = await Api.core()
|
const oauth = await Api.oauth()
|
||||||
this.$store.commit('setCore', core)
|
this.$store.commit('setOAuth', oauth)
|
||||||
this.$store.commit('setOAuth', c.oauth)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,23 @@ import VueRouter from 'vue-router'
|
||||||
import VueApexCharts from 'vue-apexcharts'
|
import VueApexCharts from 'vue-apexcharts'
|
||||||
import VueObserveVisibility from 'vue-observe-visibility'
|
import VueObserveVisibility from 'vue-observe-visibility'
|
||||||
import VueClipboard from 'vue-clipboard2'
|
import VueClipboard from 'vue-clipboard2'
|
||||||
|
import VueCookies from 'vue-cookies'
|
||||||
|
|
||||||
import App from '@/App.vue'
|
import App from '@/App.vue'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
|
||||||
import router from './routes'
|
|
||||||
import "./mixin"
|
|
||||||
import "./icons"
|
|
||||||
|
|
||||||
Vue.component('apexchart', VueApexCharts)
|
Vue.component('apexchart', VueApexCharts)
|
||||||
|
|
||||||
Vue.use(VueClipboard);
|
Vue.use(VueClipboard);
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
Vue.use(VueObserveVisibility);
|
Vue.use(VueObserveVisibility);
|
||||||
|
Vue.use(VueCookies);
|
||||||
|
Vue.$cookies.config('3d')
|
||||||
|
|
||||||
|
import router from './routes'
|
||||||
|
import "./mixin"
|
||||||
|
import "./icons"
|
||||||
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
new Vue({
|
new Vue({
|
||||||
|
|
|
@ -34,7 +34,18 @@ const routes = [
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true
|
||||||
},
|
},
|
||||||
beforeEnter: CheckAuth,
|
beforeEnter: async (to, from, next) => {
|
||||||
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
|
let tk = await Api.token()
|
||||||
|
if (to.path !== '/login' && !tk.admin) {
|
||||||
|
next('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
},
|
||||||
children: [{
|
children: [{
|
||||||
path: '',
|
path: '',
|
||||||
component: DashboardIndex,
|
component: DashboardIndex,
|
||||||
|
@ -135,9 +146,10 @@ const router = new VueRouter({
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
function CheckAuth(to, from, next) {
|
let CheckAuth = (to, from, next) => {
|
||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
let item = localStorage.getItem("statping_user")
|
let item = this.$cookies.get("statping_auth")
|
||||||
|
window.console.log(item)
|
||||||
if (to.path !== '/login' && !item) {
|
if (to.path !== '/login' && !item) {
|
||||||
next('/login')
|
next('/login')
|
||||||
return
|
return
|
||||||
|
|
|
@ -102,7 +102,6 @@ export default new Vuex.Store({
|
||||||
state.hasPublicData = bool
|
state.hasPublicData = bool
|
||||||
},
|
},
|
||||||
setCore (state, core) {
|
setCore (state, core) {
|
||||||
window.console.log('GETTING CORE')
|
|
||||||
state.core = core
|
state.core = core
|
||||||
},
|
},
|
||||||
setToken (state, token) {
|
setToken (state, token) {
|
||||||
|
@ -146,10 +145,11 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
async loadCore(context) {
|
async loadCore(context) {
|
||||||
const core = await Api.core()
|
const core = await Api.core()
|
||||||
|
const token = await Api.token()
|
||||||
context.commit("setCore", core);
|
context.commit("setCore", core);
|
||||||
context.commit('setAdmin', core.admin)
|
context.commit('setAdmin', token.admin)
|
||||||
context.commit('setCore', core)
|
context.commit('setCore', core)
|
||||||
context.commit('setUser', core.logged_in)
|
context.commit('setUser', token.token!==undefined)
|
||||||
},
|
},
|
||||||
async loadRequired(context) {
|
async loadRequired(context) {
|
||||||
const groups = await Api.groups()
|
const groups = await Api.groups()
|
||||||
|
|
|
@ -10,7 +10,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
'/oauth': {
|
'/oauth': {
|
||||||
logLevel: 'debug',
|
logLevel: 'debug',
|
||||||
target: 'http://0.0.0.0:8585'
|
target: 'http://0.0.0.0:8585/oauth/'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11838,6 +11838,11 @@ vue-codemirror@^4.0.6:
|
||||||
codemirror "^5.41.0"
|
codemirror "^5.41.0"
|
||||||
diff-match-patch "^1.0.0"
|
diff-match-patch "^1.0.0"
|
||||||
|
|
||||||
|
vue-cookies@^1.7.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-cookies/-/vue-cookies-1.7.0.tgz#dd8f147ff1579e0cbd5f352dc5dff2696d8760b8"
|
||||||
|
integrity sha512-vuEUm6wYMMrFAHFCrkzIUAy8+MgPAbBGmYXnk2M6X6O2KHbMT1wuDD2izacmsSUp6ZM02e23MJRtPRobl88VMg==
|
||||||
|
|
||||||
vue-eslint-parser@^4.0.2:
|
vue-eslint-parser@^4.0.2:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-4.0.3.tgz#80cf162e484387b2640371ad21ba1f86e0c10a61"
|
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-4.0.3.tgz#80cf162e484387b2640371ad21ba1f86e0c10a61"
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
||||||
github.com/gogo/protobuf v1.3.1 // indirect
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
github.com/golang/protobuf v1.3.5
|
github.com/golang/protobuf v1.3.5
|
||||||
github.com/gorilla/mux v1.7.4
|
github.com/gorilla/mux v1.7.4
|
||||||
|
github.com/gorilla/securecookie v1.1.1
|
||||||
github.com/gorilla/sessions v1.2.0
|
github.com/gorilla/sessions v1.2.0
|
||||||
github.com/jinzhu/gorm v1.9.12
|
github.com/jinzhu/gorm v1.9.12
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
|
|
|
@ -27,13 +27,7 @@ type apiResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiIndexHandler(r *http.Request) interface{} {
|
func apiIndexHandler(r *http.Request) interface{} {
|
||||||
coreClone := *core.App
|
return core.App
|
||||||
_, err := getJwtToken(r)
|
|
||||||
if err == nil {
|
|
||||||
coreClone.LoggedIn = true
|
|
||||||
coreClone.IsAdmin = IsAdmin(r)
|
|
||||||
}
|
|
||||||
return coreClone
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -50,6 +44,18 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
returnJson(output, w, r)
|
returnJson(output, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiUpdateOAuthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var c core.OAuth
|
||||||
|
err := DecodeJSON(r, &c)
|
||||||
|
if err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app := core.App
|
||||||
|
app.OAuth = c
|
||||||
|
sendJsonAction(app.OAuth, "update", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func apiOAuthHandler(r *http.Request) interface{} {
|
func apiOAuthHandler(r *http.Request) interface{} {
|
||||||
app := core.App
|
app := core.App
|
||||||
return app.OAuth
|
return app.OAuth
|
||||||
|
@ -78,7 +84,6 @@ func apiCoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if c.Domain != app.Domain {
|
if c.Domain != app.Domain {
|
||||||
app.Domain = c.Domain
|
app.Domain = c.Domain
|
||||||
}
|
}
|
||||||
app.OAuth = c.OAuth
|
|
||||||
app.UseCdn = null.NewNullBool(c.UseCdn.Bool)
|
app.UseCdn = null.NewNullBool(c.UseCdn.Bool)
|
||||||
app.AllowReports = null.NewNullBool(c.AllowReports.Bool)
|
app.AllowReports = null.NewNullBool(c.AllowReports.Bool)
|
||||||
utils.SentryInit(nil, app.AllowReports.Bool)
|
utils.SentryInit(nil, app.AllowReports.Bool)
|
||||||
|
|
|
@ -15,7 +15,9 @@ import (
|
||||||
|
|
||||||
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
removeJwtToken(w)
|
removeJwtToken(w)
|
||||||
http.Redirect(w, r, basePath, http.StatusSeeOther)
|
out := make(map[string]string)
|
||||||
|
out["status"] = "success"
|
||||||
|
returnJson(out, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logsHandler(w http.ResponseWriter, r *http.Request) {
|
func logsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -163,7 +165,7 @@ func removeJwtToken(w http.ResponseWriter) {
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: cookieKey,
|
Name: cookieKey,
|
||||||
Value: "",
|
Value: "",
|
||||||
Expires: utils.Now(),
|
Expires: time.Now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,8 +180,10 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaim)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaim)
|
||||||
tokenString, err := token.SignedString([]byte(jwtKey))
|
tokenString, err := token.SignedString([]byte(jwtKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log.Errorln("error setting token: ", err)
|
log.Errorln("error setting token: ", err)
|
||||||
}
|
}
|
||||||
|
user.Token = tokenString
|
||||||
|
// set cookies
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: cookieKey,
|
Name: cookieKey,
|
||||||
Value: tokenString,
|
Value: tokenString,
|
||||||
|
@ -195,9 +199,8 @@ func apiLoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
user, auth := users.AuthUser(username, password)
|
user, auth := users.AuthUser(username, password)
|
||||||
if auth {
|
if auth {
|
||||||
utils.Log.Infoln(fmt.Sprintf("User %v logged in from IP %v", user.Username, r.RemoteAddr))
|
log.Infoln(fmt.Sprintf("User %v logged in from IP %v", user.Username, r.RemoteAddr))
|
||||||
claim, token := setJwtToken(user, w)
|
claim, token := setJwtToken(user, w)
|
||||||
|
|
||||||
resp := struct {
|
resp := struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
IsAdmin bool `json:"admin"`
|
IsAdmin bool `json:"admin"`
|
||||||
|
|
|
@ -1,41 +1,48 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/sessions"
|
|
||||||
"github.com/statping/statping/types/core"
|
"github.com/statping/statping/types/core"
|
||||||
"github.com/statping/statping/types/null"
|
"github.com/statping/statping/types/null"
|
||||||
"github.com/statping/statping/types/users"
|
"github.com/statping/statping/types/users"
|
||||||
|
"github.com/statping/statping/utils"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/github"
|
"golang.org/x/oauth2/github"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
"golang.org/x/oauth2/slack"
|
"golang.org/x/oauth2/slack"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var oauthSession = sessions.NewCookieStore([]byte("statping_oauth"))
|
|
||||||
|
|
||||||
type oAuth struct {
|
type oAuth struct {
|
||||||
|
ID string
|
||||||
Email string
|
Email string
|
||||||
|
Username string
|
||||||
Token string
|
Token string
|
||||||
RefreshToken string
|
RefreshToken string
|
||||||
Valid bool
|
Valid bool
|
||||||
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
func oauthHandler(w http.ResponseWriter, r *http.Request) {
|
func oauthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
provider := vars["provider"]
|
provider := vars["provider"]
|
||||||
|
code := r.URL.Query().Get("code")
|
||||||
|
fmt.Println("code: ", code)
|
||||||
|
fmt.Println("client: ", core.App.OAuth.SlackClientID)
|
||||||
|
fmt.Println("secret: ", core.App.OAuth.SlackClientSecret)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var oauth *oAuth
|
var oauth *oAuth
|
||||||
switch provider {
|
switch provider {
|
||||||
case "google":
|
case "google":
|
||||||
err, oauth = googleOAuth(r)
|
oauth, err = googleOAuth(r)
|
||||||
case "github":
|
case "github":
|
||||||
err, oauth = githubOAuth(r)
|
oauth, err = githubOAuth(r)
|
||||||
case "slack":
|
case "slack":
|
||||||
err, oauth = slackOAuth(r)
|
oauth, err = slackOAuth(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,17 +58,18 @@ func oauthLogin(oauth *oAuth, w http.ResponseWriter, r *http.Request) {
|
||||||
log.Infoln(oauth)
|
log.Infoln(oauth)
|
||||||
user := &users.User{
|
user := &users.User{
|
||||||
Id: 0,
|
Id: 0,
|
||||||
Username: oauth.Email,
|
Username: oauth.Username,
|
||||||
Email: oauth.Email,
|
Email: oauth.Email,
|
||||||
Admin: null.NewNullBool(true),
|
Admin: null.NewNullBool(true),
|
||||||
}
|
}
|
||||||
log.Infoln(fmt.Sprintf("OAuth User %v logged in from IP %v", oauth.Email, r.RemoteAddr))
|
log.Infoln(fmt.Sprintf("OAuth User %s logged in from IP %s", oauth.Email, r.RemoteAddr))
|
||||||
setJwtToken(user, w)
|
setJwtToken(user, w)
|
||||||
|
|
||||||
http.Redirect(w, r, basePath+"dashboard", http.StatusSeeOther)
|
//returnJson(user, w, r)
|
||||||
|
http.Redirect(w, r, core.App.Domain, http.StatusPermanentRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func githubOAuth(r *http.Request) (error, *oAuth) {
|
func githubOAuth(r *http.Request) (*oAuth, error) {
|
||||||
c := *core.App
|
c := *core.App
|
||||||
code := r.URL.Query().Get("code")
|
code := r.URL.Query().Get("code")
|
||||||
|
|
||||||
|
@ -73,58 +81,94 @@ func githubOAuth(r *http.Request) (error, *oAuth) {
|
||||||
|
|
||||||
gg, err := config.Exchange(r.Context(), code)
|
gg, err := config.Exchange(r.Context(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &oAuth{
|
return &oAuth{
|
||||||
Token: gg.AccessToken,
|
Token: gg.AccessToken,
|
||||||
RefreshToken: gg.RefreshToken,
|
RefreshToken: gg.RefreshToken,
|
||||||
Valid: gg.Valid(),
|
Valid: gg.Valid(),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func googleOAuth(r *http.Request) (error, *oAuth) {
|
func googleOAuth(r *http.Request) (*oAuth, error) {
|
||||||
c := core.App
|
c := core.App
|
||||||
code := r.URL.Query().Get("code")
|
code := r.URL.Query().Get("code")
|
||||||
|
|
||||||
config := &oauth2.Config{
|
config := &oauth2.Config{
|
||||||
ClientID: c.OAuth.GithubClientID,
|
ClientID: c.OAuth.GoogleClientID,
|
||||||
ClientSecret: c.OAuth.GithubClientSecret,
|
ClientSecret: c.OAuth.GoogleClientSecret,
|
||||||
Endpoint: google.Endpoint,
|
Endpoint: google.Endpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
gg, err := config.Exchange(r.Context(), code)
|
gg, err := config.Exchange(r.Context(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &oAuth{
|
return &oAuth{
|
||||||
Token: gg.AccessToken,
|
Token: gg.AccessToken,
|
||||||
RefreshToken: gg.RefreshToken,
|
RefreshToken: gg.RefreshToken,
|
||||||
Valid: gg.Valid(),
|
Valid: gg.Valid(),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func slackOAuth(r *http.Request) (error, *oAuth) {
|
func slackOAuth(r *http.Request) (*oAuth, error) {
|
||||||
c := *core.App
|
c := core.App
|
||||||
code := r.URL.Query().Get("code")
|
code := r.URL.Query().Get("code")
|
||||||
|
|
||||||
config := &oauth2.Config{
|
config := &oauth2.Config{
|
||||||
ClientID: c.OAuth.GithubClientID,
|
ClientID: c.OAuth.SlackClientID,
|
||||||
ClientSecret: c.OAuth.GithubClientSecret,
|
ClientSecret: c.OAuth.SlackClientSecret,
|
||||||
Endpoint: slack.Endpoint,
|
Endpoint: slack.Endpoint,
|
||||||
|
RedirectURL: c.Domain + basePath + "oauth/slack",
|
||||||
|
Scopes: []string{"identity.basic"},
|
||||||
}
|
}
|
||||||
|
|
||||||
gg, err := config.Exchange(r.Context(), code)
|
gg, err := config.Exchange(r.Context(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &oAuth{
|
oauther := &oAuth{
|
||||||
Token: gg.AccessToken,
|
Token: gg.AccessToken,
|
||||||
RefreshToken: gg.RefreshToken,
|
RefreshToken: gg.RefreshToken,
|
||||||
Valid: gg.Valid(),
|
Valid: gg.Valid(),
|
||||||
|
Type: gg.Type(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return oauther.slackIdentity()
|
||||||
|
}
|
||||||
|
|
||||||
|
// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
|
||||||
|
func (a *oAuth) slackIdentity() (*oAuth, error) {
|
||||||
|
url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
|
||||||
|
out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true)
|
||||||
|
if err != nil {
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var i *slackIdentity
|
||||||
|
if err := json.Unmarshal(out, &i); err != nil {
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
a.Email = i.User.Email
|
||||||
|
a.ID = i.User.ID
|
||||||
|
a.Username = i.User.Name
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type slackIdentity struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
} `json:"user"`
|
||||||
|
Team struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
} `json:"team"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func secureToken(w http.ResponseWriter, r *http.Request) {
|
func secureToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ func staticAssets(src string) http.Handler {
|
||||||
func Router() *mux.Router {
|
func Router() *mux.Router {
|
||||||
dir := utils.Directory
|
dir := utils.Directory
|
||||||
CacheStorage = NewStorage()
|
CacheStorage = NewStorage()
|
||||||
|
|
||||||
r := mux.NewRouter().StrictSlash(true)
|
r := mux.NewRouter().StrictSlash(true)
|
||||||
|
|
||||||
authUser := utils.Params.GetString("AUTH_USERNAME")
|
authUser := utils.Params.GetString("AUTH_USERNAME")
|
||||||
|
@ -74,16 +75,19 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api", scoped(apiIndexHandler))
|
r.Handle("/api", scoped(apiIndexHandler))
|
||||||
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
|
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
|
||||||
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
|
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
|
||||||
api.Handle("/api/logout", http.HandlerFunc(logoutHandler))
|
api.Handle("/api/logout", authenticated(logoutHandler, false))
|
||||||
api.Handle("/api/renew", authenticated(apiRenewHandler, false))
|
api.Handle("/api/renew", authenticated(apiRenewHandler, false))
|
||||||
api.Handle("/api/cache", authenticated(apiCacheHandler, false)).Methods("GET")
|
api.Handle("/api/cache", authenticated(apiCacheHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
||||||
api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST")
|
api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST")
|
||||||
api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET")
|
|
||||||
api.Handle("/oauth/{provider}", http.HandlerFunc(oauthHandler))
|
|
||||||
api.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET")
|
api.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
||||||
|
|
||||||
|
// API OAUTH Routes
|
||||||
|
api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET")
|
||||||
|
api.Handle("/api/oauth", authenticated(apiUpdateOAuthHandler, false)).Methods("POST")
|
||||||
|
api.Handle("/oauth/{provider}", http.HandlerFunc(oauthHandler))
|
||||||
|
|
||||||
// API SCSS and ASSETS Routes
|
// API SCSS and ASSETS Routes
|
||||||
api.Handle("/api/theme", authenticated(apiThemeViewHandler, false)).Methods("GET")
|
api.Handle("/api/theme", authenticated(apiThemeViewHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/theme", authenticated(apiThemeSaveHandler, false)).Methods("POST")
|
api.Handle("/api/theme", authenticated(apiThemeSaveHandler, false)).Methods("POST")
|
||||||
|
|
|
@ -31,8 +31,6 @@ type Core struct {
|
||||||
Setup bool `gorm:"-" json:"setup"`
|
Setup bool `gorm:"-" json:"setup"`
|
||||||
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
|
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
|
||||||
UseCdn null.NullBool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
|
UseCdn null.NullBool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
|
||||||
LoggedIn bool `gorm:"-" json:"logged_in"`
|
|
||||||
IsAdmin bool `gorm:"-" json:"admin"`
|
|
||||||
AllowReports null.NullBool `gorm:"column:allow_reports;default:false" json:"allow_reports,omitempty"`
|
AllowReports null.NullBool `gorm:"column:allow_reports;default:false" json:"allow_reports,omitempty"`
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||||
|
|
|
@ -16,4 +16,5 @@ type User struct {
|
||||||
Admin null.NullBool `gorm:"column:administrator" json:"admin,omitempty"`
|
Admin null.NullBool `gorm:"column:administrator" json:"admin,omitempty"`
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||||
|
Token string `gorm:"-" json:"token"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue