Skip to content

Commit

Permalink
Add require login feature to see gists
Browse files Browse the repository at this point in the history
  • Loading branch information
thomiceli committed Apr 28, 2023
1 parent 64d0818 commit 333efea
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 23 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ A self-hosted pastebin **powered by Git**. [Try it here](https://opengist.thomic
* Avatars
* Responsive UI
* Enable or disable signups
* Restrict or unrestrict snippets visibility to anonymous users
* Admin panel : delete users/gists; clean database/filesystem by syncing gists
* SQLite database
* Logging
Expand Down
18 changes: 17 additions & 1 deletion internal/models/admin_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type AdminSetting struct {

const (
SettingDisableSignup = "disable-signup"
SettingRequireLogin = "require-login"
)

func GetSetting(key string) (string, error) {
Expand All @@ -19,9 +20,24 @@ func GetSetting(key string) (string, error) {
return setting.Value, err
}

func GetSettings() (map[string]string, error) {
var settings []AdminSetting
err := db.Find(&settings).Error
if err != nil {
return nil, err
}

result := make(map[string]string)
for _, setting := range settings {
result[setting.Key] = setting.Value
}

return result, nil
}

func UpdateSetting(key string, value string) error {
return db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "key"}}, // key colume
Columns: []clause.Column{{Name: "key"}}, // key column
DoUpdates: clause.AssignmentColumns([]string{"value"}),
}).Create(&AdminSetting{
Key: key,
Expand Down
1 change: 1 addition & 0 deletions internal/models/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func Setup(dbpath string) error {
// Default admin setting values
return initAdminSettings(map[string]string{
SettingDisableSignup: "0",
SettingRequireLogin: "0",
})
}

Expand Down
7 changes: 6 additions & 1 deletion internal/ssh/git_ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ func runGitCommand(ch ssh.Channel, gitCmd string, keyID uint, ip string) error {
return errors.New("gist not found")
}

if verb == "receive-pack" {
requireLogin, err := models.GetSetting(models.SettingRequireLogin)
if err != nil {
return errors.New("internal server error")
}

if verb == "receive-pack" || requireLogin == "1" {
user, err := models.GetUserBySSHKeyID(keyID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
Expand Down
12 changes: 6 additions & 6 deletions internal/web/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func register(ctx echo.Context) error {
}

func processRegister(ctx echo.Context) error {
if getData(ctx, "signupDisabled") == true {
if getData(ctx, "DisableSignup") == true {
return errorRes(403, "Signing up is disabled", nil)
}

Expand Down Expand Up @@ -148,6 +148,10 @@ func oauthCallback(ctx echo.Context) error {
// if user is not in database, create it
userDB, err := models.GetUserByProvider(user.UserID, user.Provider)
if err != nil {
if getData(ctx, "DisableSignup") == true {
return errorRes(403, "Signing up is disabled", nil)
}

if !errors.Is(err, gorm.ErrRecordNotFound) {
return errorRes(500, "Cannot get user", err)
}
Expand All @@ -166,10 +170,6 @@ func oauthCallback(ctx echo.Context) error {
}

if err = userDB.Create(); err != nil {
if getData(ctx, "signupDisabled") == true {
return errorRes(403, "Signing up is disabled", nil)
}

if models.IsUniqueConstraintViolation(err) {
addFlash(ctx, "Username "+user.NickName+" already exists in Opengist", "error")
return redirect(ctx, "/login")
Expand Down Expand Up @@ -281,7 +281,7 @@ func oauth(ctx echo.Context) error {
}
}

ctxValue := context.WithValue(ctx.Request().Context(), providerKey, provider)
ctxValue := context.WithValue(ctx.Request().Context(), gothic.ProviderParamKey, provider)
ctx.SetRequest(ctx.Request().WithContext(ctxValue))
if provider != "github" && provider != "gitea" {
return errorRes(400, "Unsupported provider", nil)
Expand Down
5 changes: 3 additions & 2 deletions internal/web/git_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ func gitHttp(ctx echo.Context) error {

gist := getData(ctx, "gist").(*models.Gist)

noAuth := ctx.QueryParam("service") == "git-upload-pack" ||
noAuth := (ctx.QueryParam("service") == "git-upload-pack" ||
strings.HasSuffix(ctx.Request().URL.Path, "git-upload-pack") ||
ctx.Request().Method == "GET"
ctx.Request().Method == "GET") &&
!getData(ctx, "RequireLogin").(bool)

repositoryPath := git.RepositoryPath(gist.User.Username, gist.Uuid)

Expand Down
27 changes: 20 additions & 7 deletions internal/web/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ func Start() {
g2.PUT("/set-setting", adminSetSetting)
}

g1.GET("/all", allGists)
g1.GET("/:user", allGists)
g1.GET("/all", allGists, checkRequireLogin)
g1.GET("/:user", allGists, checkRequireLogin)

g3 := g1.Group("/:user/:gistname")
{
g3.Use(gistInit)
g3.Use(checkRequireLogin, gistInit)
g3.GET("", gistIndex)
g3.GET("/rev/:revision", gistIndex)
g3.GET("/revisions", revisions)
Expand Down Expand Up @@ -243,11 +243,9 @@ func dataInit(next echo.HandlerFunc) echo.HandlerFunc {
ctx.SetRequest(ctx.Request().WithContext(ctxValue))
setData(ctx, "loadStartTime", time.Now())

disableSignup, err := models.GetSetting(models.SettingDisableSignup)
if err != nil {
return errorRes(500, "Cannot read setting from database", err)
if err := loadSettings(ctx); err != nil {
return errorRes(500, "Cannot read settings from database", err)
}
setData(ctx, "signupDisabled", disableSignup == "1")

setData(ctx, "githubOauth", config.C.GithubClientKey != "" && config.C.GithubSecret != "")
setData(ctx, "giteaOauth", config.C.GiteaClientKey != "" && config.C.GiteaSecret != "")
Expand Down Expand Up @@ -318,6 +316,21 @@ func logged(next echo.HandlerFunc) echo.HandlerFunc {
}
}

func checkRequireLogin(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
if user := getUserLogged(ctx); user != nil {
return next(ctx)
}

require := getData(ctx, "RequireLogin")
if require == true {
addFlash(ctx, "You must be logged in to access gists", "error")
return redirect(ctx, "/login")
}
return next(ctx)
}
}

func cacheControl(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.Response().Header().Set(echo.HeaderCacheControl, "public, max-age=31536000")
Expand Down
16 changes: 14 additions & 2 deletions internal/web/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import (
"strings"
)

type providerKeyType string
type dataTypeKey string

const providerKey providerKeyType = "provider"
const dataKey dataTypeKey = "data"

func setData(ctx echo.Context, key string, value any) {
Expand Down Expand Up @@ -110,6 +108,20 @@ func deleteCsrfCookie(ctx echo.Context) {
ctx.SetCookie(&http.Cookie{Name: "_csrf", Path: "/", MaxAge: -1})
}

func loadSettings(ctx echo.Context) error {
settings, err := models.GetSettings()
if err != nil {
return err
}

for key, value := range settings {
s := strings.ReplaceAll(key, "-", " ")
s = title.String(s)
setData(ctx, strings.ReplaceAll(s, " ", ""), value == "1")
}
return nil
}

type OpengistValidator struct {
v *validator.Validate
}
Expand Down
1 change: 1 addition & 0 deletions public/admin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
document.addEventListener('DOMContentLoaded', () => {
registerDomSetting(document.getElementById('disable-signup') as HTMLInputElement);
registerDomSetting(document.getElementById('require-login') as HTMLInputElement);
});

const setSetting = (key: string, value: string) => {
Expand Down
2 changes: 1 addition & 1 deletion templates/base/base_header.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
</svg>
</a>
{{ else }}
{{ if not .signupDisabled }}
{{ if not .DisableSignup }}
<a href="/register" class="inline-flex text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
<p class="text-slate-300 mr-1">Register</p>
</a>
Expand Down
6 changes: 5 additions & 1 deletion templates/pages/admin_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@
<div class="space-y-2">
<div>
<label for="disable-signup" class="text-sm text-slate-300">Disable signup</label>
<input type="checkbox" id="disable-signup" name="disable-signup" {{ if .signupDisabled }}checked="checked"{{ end }} class="ml-1 h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" />
<input type="checkbox" id="disable-signup" name="disable-signup" {{ if .DisableSignup }}checked="checked"{{ end }} class="ml-1 h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" />
</div>
<div>
<label for="disable-signup" class="text-sm text-slate-300">Login required</label>
<input type="checkbox" id="require-login" name="require-login" {{ if .RequireLogin }}checked="checked"{{ end }} class="ml-1 h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" />
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions templates/pages/auth_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h1 class="text-2xl font-bold leading-tight text-slate-300">

</header>
<main class="mt-4">
{{ if and .signupDisabled (ne .title "Login") }}
{{ if and .DisableSignup (ne .title "Login") }}
<p class="italic">Administrator has disabled signing up</p>
{{ else }}
<div class="sm:col-span-6">
Expand All @@ -33,7 +33,7 @@ <h1 class="text-2xl font-bold leading-tight text-slate-300">
<div class="flex-auto">
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Login</button>
</div>
{{ if not .signupDisabled }}
{{ if not .DisableSignup }}
<span class="float-right text-sm py-2 underline"><a href="/register">Register instead →</a></span>
{{ end }}
</div>
Expand Down

0 comments on commit 333efea

Please sign in to comment.