This commit is contained in:
Michael Zhang 2020-12-11 04:16:49 -06:00
commit 892ec22882
Signed by: michael
GPG Key ID: BDA47A31A3C8EE6B
21 changed files with 6742 additions and 0 deletions

2
backend/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/backend
/config.toml

4
backend/Makefile Normal file
View File

@ -0,0 +1,4 @@
SOURCES := $(shell find -name "*.go" -print)
backend: $(SOURCES)
go build -o $@

42
backend/config/config.go Normal file
View File

@ -0,0 +1,42 @@
package config
import (
"fmt"
"io/ioutil"
"os"
"github.com/BurntSushi/toml"
)
type Config struct {
BaseUrl string `toml:"base_url"`
SessionSecret string `toml:"session_secret"`
Oauth OauthConfig `toml:"oauth"`
}
type OauthConfig struct {
ClientId string `toml:"client_id"`
ClientSecret string `toml:"client_secret"`
}
func ReadConfig(path string) (config Config, err error) {
file, err := os.Open(path)
if err != nil {
err = fmt.Errorf("couldn't open file %s: %w", path, err)
return
}
data, err := ioutil.ReadAll(file)
if err != nil {
err = fmt.Errorf("couldn't read data from %s: %w", path, err)
return
}
err = toml.Unmarshal(data, &config)
if err != nil {
err = fmt.Errorf("couldn't parse config data from %s: %w", path, err)
return
}
return
}

11
backend/go.mod Normal file
View File

@ -0,0 +1,11 @@
module backend
go 1.14
require (
github.com/BurntSushi/toml v0.3.1
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19
github.com/gin-gonic/gin v1.6.3
github.com/gorilla/sessions v1.2.1 // indirect
)

54
backend/go.sum Normal file
View File

@ -0,0 +1,54 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19 h1:J2LPEOcQmWaooBnBtUDV9KHFEnP5LYTZY03GiQ0oQBw=
github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

95
backend/main.go Normal file
View File

@ -0,0 +1,95 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"backend/config"
)
type Web struct {
config *config.Config
hc *http.Client
}
func main() {
cfgPath := flag.String("config", "config.toml", "Path to the config file (defaults to config.toml)")
flag.Parse()
cfg, err := config.ReadConfig(*cfgPath)
if err != nil {
log.Fatal(err)
}
hc := &http.Client{
Timeout: 10 * time.Second,
}
web := &Web{
config: &cfg,
hc: hc,
}
r := gin.Default()
r.Use(gin.Recovery())
r.Use(sessions.Sessions("mysession", sessions.NewCookieStore([]byte(web.config.SessionSecret))))
r.GET("/login", web.loginHandler)
r.GET("/login/callback", web.loginCallbackHandler)
r.Run("127.0.0.1:1235")
}
func (web *Web) loginHandler(c *gin.Context) {
url := url.URL{
Scheme: "https",
Host: "osu.ppy.sh",
Path: "/oauth/authorize",
}
q := url.Query()
q.Set("client_id", web.config.Oauth.ClientId)
q.Set("redirect_uri", web.config.BaseUrl+"/login/callback")
q.Set("response_type", "code")
q.Set("scope", "identify public")
q.Set("state", "urmom")
url.RawQuery = q.Encode()
fmt.Println("redirecting to", url.String())
c.Redirect(http.StatusTemporaryRedirect, url.String())
}
func (web *Web) loginCallbackHandler(c *gin.Context) {
receivedCode := c.Query("code")
bodyQuery := url.Values{}
bodyQuery.Set("client_id", web.config.Oauth.ClientId)
bodyQuery.Set("client_secret", web.config.Oauth.ClientSecret)
bodyQuery.Set("code", receivedCode)
bodyQuery.Set("grant_type", "authorization_code")
bodyQuery.Set("redirect_uri", web.config.BaseUrl+"/login/callback")
body := strings.NewReader(bodyQuery.Encode())
resp, _ := web.hc.Post("https://osu.ppy.sh/oauth/token", "application/x-www-form-urlencoded", body)
respBody, _ := ioutil.ReadAll(resp.Body)
type OsuToken struct {
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
var token OsuToken
_ = json.Unmarshal(respBody, &token)
fmt.Println("TOKEN", token)
session := sessions.Default(c)
session.Set("access_token", token.AccessToken)
session.Save()
c.Redirect(http.StatusTemporaryRedirect, "/")
}

13
backend/models.go Normal file
View File

@ -0,0 +1,13 @@
package main
import "github.com/jinzhu/gorm"
type UserModel struct {
OsuID uint `gorm:"primary_key"`
Username string
AccessToken string
}
func AutoMigrate(db *gorm.DB) {
db.AutoMigrate(&UserModel{})
}

3
frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/node_modules
/.cache
/dist

1
frontend/.ignore Normal file
View File

@ -0,0 +1 @@
package-lock.json

38
frontend/App.vue Normal file
View File

@ -0,0 +1,38 @@
<template>
<div>
<b-navbar type="dark" variant="dark">
<b-container>
<b-navbar-brand to="home">OsuTier</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav class="ml-auto">
<b-nav-item v-on:click="redirectLogin">Login with OSU</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-container>
</b-navbar>
<b-container id="body-container">
<router-view />
</b-container>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
@Component
export default class App extends Vue {
redirectLogin() {
location.href = "/api/login";
}
}
</script>
<style lang="scss" scoped>
#body-container {
margin-top: 20px;
}
</style>

19
frontend/app.js Normal file
View File

@ -0,0 +1,19 @@
import Vue from "vue";
import { BootstrapVue, IconsPlugin } from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
new Vue({
el: "#app",
router,
store,
render: (h) => h(App),
});

18
frontend/common/api.js Normal file
View File

@ -0,0 +1,18 @@
import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
class Api {
init(baseUrl) {
Vue.use(VueAxios, axios);
this.baseUrl = baseUrl;
}
get(url) {
}
}
let instance = Api();
Object.freeze(instance);
export default instance;

15
frontend/common/jwt.js Normal file
View File

@ -0,0 +1,15 @@
const ID_TOKEN_KEY = "id_token";
export const getToken = () => {
return window.localStorage.getItem(ID_TOKEN_KEY);
};
export const saveToken = token => {
window.localStorage.setItem(ID_TOKEN_KEY, token);
};
export const destroyToken = () => {
window.localStorage.removeItem(ID_TOKEN_KEY);
};
export default { getToken, saveToken, destroyToken };

9
frontend/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="app"></div>
<script src="app.js"></script>
</body>
</html>

6360
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
frontend/package.json Normal file
View File

@ -0,0 +1,20 @@
{
"scripts": {
"serve": "parcel index.html"
},
"dependencies": {
"bootstrap-vue": "^2.20.1",
"parcel": "^1.12.4",
"vue": "^2.6.12",
"vue-class-component": "^7.2.6",
"vue-hot-reload-api": "^2.3.4",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.4.9"
},
"devDependencies": {
"@vue/component-compiler-utils": "^3.2.0",
"sass": "^1.30.0",
"typescript": "^4.1.2",
"vue-template-compiler": "^2.6.12"
}
}

15
frontend/router.js Normal file
View File

@ -0,0 +1,15 @@
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
export default new VueRouter({
mode: "history",
routes: [
{
path: "/",
name: "home",
component: () => import ("~/views/Home"),
},
],
});

View File

@ -0,0 +1 @@
export const CHECK_AUTH = "checkAuth";

View File

@ -0,0 +1,11 @@
import Api from "~/common/api";
import { LOGIN, CHECK_AUTH } from "./actions.type";
const actions = {
[CHECK_AUTH](ctx) {
}
};
export default { actions };

0
frontend/store/index.js Normal file
View File

11
frontend/views/Home.vue Normal file
View File

@ -0,0 +1,11 @@
<template>
<div>urmom</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { mapState } from "vuex";
@Component
export default class Home extends Vue {}
</script>