mirror of
https://github.com/status-im/fathom.git
synced 2025-02-28 19:10:36 +00:00
add basic JWT auth structure
This commit is contained in:
parent
2ff06c02d0
commit
5d6796dfe5
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
static/assets/js
|
||||
static/assets/css
|
||||
.*
|
||||
|
35
ana.go
35
ana.go
@ -3,28 +3,35 @@ package main
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"log"
|
||||
"github.com/dannyvankooten/ana/core"
|
||||
"github.com/dannyvankooten/ana/api"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
// TODO: Authentication.
|
||||
|
||||
func main() {
|
||||
db := core.SetupDatabaseConnection()
|
||||
defer db.Close()
|
||||
// test .env file
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
|
||||
r := mux.NewRouter()
|
||||
db := core.SetupDatabaseConnection()
|
||||
defer db.Close()
|
||||
|
||||
// register routes
|
||||
r.HandleFunc("/collect", api.CollectHandler).Methods("GET")
|
||||
r.HandleFunc("/api/visits/count/day", api.GetVisitsDayCountHandler).Methods("GET")
|
||||
r.HandleFunc("/api/visits/count/realtime", api.GetVisitsRealtimeCount).Methods("GET")
|
||||
r.HandleFunc("/api/visits", api.GetVisitsHandler).Methods("GET")
|
||||
r.HandleFunc("/api/pageviews", api.GetPageviewsHandler).Methods("GET")
|
||||
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
|
||||
r.Handle("/", http.FileServer(http.Dir("./views/")))
|
||||
r := mux.NewRouter()
|
||||
|
||||
http.ListenAndServe(":8080", handlers.LoggingHandler(os.Stdout, r))
|
||||
// register routes
|
||||
r.Handle("/token", api.GetTokenHandler).Methods("GET")
|
||||
r.HandleFunc("/collect", api.CollectHandler).Methods("GET")
|
||||
r.Handle("/api/visits/count/day", api.Authorize(api.GetVisitsDayCountHandler)).Methods("GET")
|
||||
r.Handle("/api/visits/count/realtime", api.Authorize(api.GetVisitsRealtimeCount)).Methods("GET")
|
||||
r.Handle("/api/visits", api.Authorize(api.GetVisitsHandler)).Methods("GET")
|
||||
r.Handle("/api/pageviews", api.Authorize(api.GetPageviewsHandler)).Methods("GET")
|
||||
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
|
||||
r.Handle("/", http.FileServer(http.Dir("./views/")))
|
||||
|
||||
http.ListenAndServe(":8080", handlers.LoggingHandler(os.Stdout, r))
|
||||
}
|
||||
|
51
api/auth.go
Normal file
51
api/auth.go
Normal file
@ -0,0 +1,51 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/request"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Authorize(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, keyLookupFunc)
|
||||
|
||||
if err == nil && token.Valid {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
})
|
||||
}
|
||||
|
||||
func getSigningKey() []byte {
|
||||
return []byte(os.Getenv("APP_SECRET_KEY"))
|
||||
}
|
||||
|
||||
/* Handlers */
|
||||
var GetTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
|
||||
// TODO: Check with database here.
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"admin": true,
|
||||
"name": "Danny",
|
||||
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||
})
|
||||
|
||||
/* Sign the token with our secret */
|
||||
tokenString, _ := token.SignedString(getSigningKey())
|
||||
|
||||
/* Finally, write the token to the browser window */
|
||||
w.Write([]byte(tokenString))
|
||||
})
|
||||
|
||||
|
||||
func keyLookupFunc(t *jwt.Token) (interface{}, error) {
|
||||
// Look up key in database.
|
||||
// TODO
|
||||
|
||||
//
|
||||
return getSigningKey(), nil
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// URL: /api/pageviews
|
||||
func GetPageviewsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var GetPageviewsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
stmt, err := core.DB.Prepare(`SELECT
|
||||
path,
|
||||
COUNT(ip_address) AS pageviews,
|
||||
@ -35,4 +35,4 @@ func GetPageviewsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(results)
|
||||
}
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// URL: /api/visits
|
||||
func GetVisitsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var GetVisitsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
stmt, err := core.DB.Prepare(`SELECT
|
||||
id,
|
||||
COALESCE(browser_name, '') AS browser_name,
|
||||
@ -48,20 +48,20 @@ func GetVisitsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(results)
|
||||
}
|
||||
})
|
||||
|
||||
// URL: /api/visits/count/realtime
|
||||
func GetVisitsRealtimeCount(w http.ResponseWriter, r *http.Request) {
|
||||
var GetVisitsRealtimeCount = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
row := core.DB.QueryRow(`SELECT COUNT(DISTINCT(ip_address)) FROM visits WHERE timestamp >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 3 HOUR_MINUTE)`)
|
||||
var result int
|
||||
row.Scan(&result)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
})
|
||||
|
||||
// URL: /api/visits/count/day
|
||||
func GetVisitsDayCountHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var GetVisitsDayCountHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
stmt, err := core.DB.Prepare(`SELECT
|
||||
COUNT(*) AS count, DATE_FORMAT(timestamp, '%Y-%m-%d') AS date_group
|
||||
FROM visits
|
||||
@ -91,4 +91,4 @@ func GetVisitsDayCountHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(results)
|
||||
}
|
||||
})
|
||||
|
21
assets/js/components/login.js
Normal file
21
assets/js/components/login.js
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { Component } from 'react'
|
||||
|
||||
class Login extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div className="block">
|
||||
<h2>Login</h2>
|
||||
<p>
|
||||
<a href="">Sign in</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Login
|
@ -6,13 +6,37 @@ import RealtimeVisitsCount from './components/realtime-visits.js';
|
||||
import VisitsList from './components/visits-list.js';
|
||||
import PageviewsList from './components/pageviews.js';
|
||||
import VisitsGraph from './components/visits-graph.js';
|
||||
import Login from './components/login.js';
|
||||
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { idToken: null }
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.state.idToken) {
|
||||
return (
|
||||
<div className="container">
|
||||
<h1>Ana</h1>
|
||||
<RealtimeVisitsCount />
|
||||
<VisitsGraph />
|
||||
<PageviewsList />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="container">
|
||||
<Login />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div className="container">
|
||||
<h1>Ana</h1>
|
||||
<RealtimeVisitsCount />
|
||||
<VisitsGraph />
|
||||
<PageviewsList />
|
||||
</div>,
|
||||
<App />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user