Skip to content

Commit

Permalink
Sign in with Google Button
Browse files Browse the repository at this point in the history
  • Loading branch information
bbengfort committed Feb 28, 2024
1 parent 64fdbf2 commit 54c7a0d
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 207 deletions.
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/rotationalio/rtnl.link

go 1.21.1

replace cloud.google.com/go => cloud.google.com/go v0.100.2

require (
github.com/dgraph-io/badger/v4 v4.2.0
github.com/gin-contrib/cors v1.5.0
Expand All @@ -17,9 +19,12 @@ require (
github.com/urfave/cli/v2 v2.26.0
github.com/vmihailenco/msgpack/v5 v5.4.1
golang.org/x/crypto v0.17.0
google.golang.org/api v0.126.0
)

require (
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand All @@ -42,9 +47,12 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand All @@ -63,8 +71,10 @@ require (
go.opencensus.io v0.24.0 // indirect
golang.org/x/arch v0.6.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/protobuf v1.31.0 // indirect
Expand Down
197 changes: 114 additions & 83 deletions go.sum

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pkg/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ type PageQuery struct {
NextPageToken string `json:"next_page_token" url:"next_page_token,omitempty" form:"next_page_token"`
}

// LoginForm to check if an API key is valid.
// LoginForm is used for Google to submit an id token back to the server.
type LoginForm struct {
APIKey string `json:"apikey" url:"apikey" form:"apikey"`
Credential string `json:"credential" url:"credential" form:"credential"`
Next string `json:"next" url:"next" form:"next"`
}

//===========================================================================
Expand Down
47 changes: 41 additions & 6 deletions pkg/api/v1/web.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
package api

import (
"net/url"
"sync"

"github.com/rotationalio/rtnl.link/pkg"
"github.com/rotationalio/rtnl.link/pkg/config"
)

var (
prepare sync.Once
webData WebData
loginData LoginData
)

func Prepare(conf config.Config) {
prepare.Do(func() {
loginURI, _ := url.Parse(conf.Origin)
loginURI.Path = "/login"

webData = WebData{
Version: pkg.Version(),
}

loginData = LoginData{
WebData: webData,
GoogleClientID: conf.GoogleClientID,
LoginURI: loginURI.String(),
}
})
}

type WebData struct {
Version string
}

func NewWebData() WebData {
return WebData{
Version: pkg.Version(),
}
func GetWebData() WebData {
return webData
}

type LoginData struct {
WebData
GoogleClientID string
LoginURI string
}

func GetLoginData() LoginData {
return loginData
}

type InfoDetail struct {
Expand All @@ -21,7 +56,7 @@ type InfoDetail struct {

func (s *ShortURL) WebData() InfoDetail {
return InfoDetail{
WebData: NewWebData(),
WebData: GetWebData(),
Info: s,
}
}
Expand All @@ -34,7 +69,7 @@ type LinkList struct {

func (s *ShortURLList) WebData() LinkList {
return LinkList{
WebData: NewWebData(),
WebData: GetWebData(),
URLs: s.URLs,
Page: s.Page,
}
Expand Down
28 changes: 15 additions & 13 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,21 @@ const prefix = "rtnl"
// values that are omitted. The Config should be validated in preparation for running
// the server to ensure that all server operations work as expected.
type Config struct {
Maintenance bool `default:"false" yaml:"maintenance"`
Mode string `default:"release"`
LogLevel logger.LevelDecoder `split_words:"true" default:"info" yaml:"log_level"`
ConsoleLog bool `split_words:"true" default:"false" yaml:"console_log"`
BindAddr string `split_words:"true" default:":8765" yaml:"bind_addr"`
AllowOrigins []string `split_words:"true" default:"http://localhost:8765"`
Origin string `default:"https://rtnl.link"`
AltOrigin string `split_words:"true" default:"https://r8l.co"`
Storage StorageConfig
Ensign EnsignConfig
processed bool
originURL *url.URL
altURL *url.URL
Maintenance bool `default:"false" yaml:"maintenance"`
Mode string `default:"release"`
LogLevel logger.LevelDecoder `split_words:"true" default:"info" yaml:"log_level"`
ConsoleLog bool `split_words:"true" default:"false" yaml:"console_log"`
BindAddr string `split_words:"true" default:":8765" yaml:"bind_addr"`
AllowOrigins []string `split_words:"true" default:"http://localhost:8765"`
Origin string `default:"https://rtnl.link"`
AltOrigin string `split_words:"true" default:"https://r8l.co"`
GoogleClientID string `split_words:"true" required:"true"`
AllowedDomain string `split_words:"true" default:"rotational.io"`
Storage StorageConfig
Ensign EnsignConfig
processed bool
originURL *url.URL
altURL *url.URL
}

type StorageConfig struct {
Expand Down
4 changes: 4 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var testEnv = map[string]string{
"RTNL_ALLOW_ORIGINS": "http://localhost:8888",
"RTNL_ORIGIN": "http://localhost:8888",
"RTNL_ALT_ORIGIN": "http://127.0.0.1:8888",
"RTNL_GOOGLE_CLIENT_ID": "1234-testing.apps.googleusercontent.com",
"RTNL_ALLOWED_DOMAIN": "example.com",
"RTNL_STORAGE_READ_ONLY": "true",
"RTNL_STORAGE_DATA_PATH": "/data/db",
"RTNL_ENSIGN_PATH": "/credentials/ensign.json",
Expand All @@ -45,6 +47,8 @@ func TestConfig(t *testing.T) {
require.Equal(t, []string{testEnv["RTNL_ALLOW_ORIGINS"]}, conf.AllowOrigins)
require.Equal(t, testEnv["RTNL_ORIGIN"], conf.Origin)
require.Equal(t, testEnv["RTNL_ALT_ORIGIN"], conf.AltOrigin)
require.Equal(t, testEnv["RTNL_GOOGLE_CLIENT_ID"], conf.GoogleClientID)
require.Equal(t, testEnv["RTNL_ALLOWED_DOMAIN"], conf.AllowedDomain)
require.True(t, conf.Storage.ReadOnly)
require.Equal(t, testEnv["RTNL_STORAGE_DATA_PATH"], conf.Storage.DataPath)
require.True(t, conf.Ensign.Maintenance)
Expand Down
4 changes: 4 additions & 0 deletions pkg/rtnl/rtnl.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/rotationalio/rtnl.link/pkg"
"github.com/rotationalio/rtnl.link/pkg/api/v1"
"github.com/rotationalio/rtnl.link/pkg/config"
"github.com/rotationalio/rtnl.link/pkg/logger"
"github.com/rotationalio/rtnl.link/pkg/storage"
Expand Down Expand Up @@ -68,6 +69,9 @@ func New(conf config.Config) (s *Server, err error) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}

// Prepare the API to generate correct web context data
api.Prepare(conf)

// Create and configure the gin router
gin.SetMode(conf.Mode)
router := gin.New()
Expand Down
24 changes: 0 additions & 24 deletions pkg/rtnl/static/js/login.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,3 @@
const API_STORAGE_KEY = "rtnlapistoragekey";

(function() {

// Handle responses from the login form.
document.body.addEventListener("htmx:afterRequest", function(e) {
if (e.detail.failed) {
// Handle error from the server
let message = "could not complete request, please try again later"
if (e.detail.xhr.response) {
const data = JSON.parse(e.detail.xhr.response);
message = data.error;
}

let elem = document.getElementById("login-error")
elem.innerText = message;
elem.classList.remove("hidden");
return
}

// Otherwise the API key is valid and can be set on local storage.
const data = JSON.parse(e.detail.xhr.response);
window.localStorage.setItem(API_STORAGE_KEY, data.apikey);
window.location.href = "/"
})

})();
34 changes: 2 additions & 32 deletions pkg/rtnl/static/js/main.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
const API_STORAGE_KEY = "rtnlapistoragekey";

function APIKey() {
return window.localStorage.getItem(API_STORAGE_KEY);
}

// Adds additional headers to the requests made by htmx
document.body.addEventListener('htmx:configRequest', function(e) {
e.detail.headers['Accept'] = "text/html";

let apikey = APIKey()
if (apikey) {
e.detail.headers['Authorization'] = 'Bearer ' + APIKey();
}
});

// Handle clicks to the logout button in the header
document.getElementById("logout").addEventListener("click", function(e) {
e.preventDefault()
window.localStorage.removeItem(API_STORAGE_KEY)
window.location.href = "/login"
return false;
});

// Checks if there is an API key, and if not, redirects to the login page.
(function() {
let apikey = APIKey();
if (!apikey) {
window.location.href = "/login"
} else {
console.info("link shortening application logged in and ready")
}
})();

console.info("link shortening application logged in and ready");
})();
Loading

0 comments on commit 54c7a0d

Please sign in to comment.