aboutsummaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2020-06-27 23:09:22 +0200
committerGitHub <noreply@github.com>2020-06-27 23:09:22 +0200
commitc0dbc149d5c0c3610476ba14a800c9ba803a2c2c (patch)
treec07587da30eae7a37c2597d110ef1e66be3b4b8f /commands
parent23228101a2a38a139f6fc2cafc18e9f08d911089 (diff)
parent3aaf775857d186ad416133935e73ed1b063938c6 (diff)
downloadgit-bug-c0dbc149d5c0c3610476ba14a800c9ba803a2c2c.tar.gz
Merge pull request #407 from lukegb/fix-402
Add support for read-only mode for web UI.
Diffstat (limited to 'commands')
-rw-r--r--commands/webui.go159
1 files changed, 28 insertions, 131 deletions
diff --git a/commands/webui.go b/commands/webui.go
index 5d3d4b4a..83480e08 100644
--- a/commands/webui.go
+++ b/commands/webui.go
@@ -1,11 +1,8 @@
package commands
import (
- "bytes"
"context"
- "encoding/json"
"fmt"
- "io/ioutil"
"log"
"net/http"
"os"
@@ -18,16 +15,20 @@ import (
"github.com/skratchdot/open-golang/open"
"github.com/spf13/cobra"
- "github.com/MichaelMure/git-bug/graphql"
+ "github.com/MichaelMure/git-bug/api/auth"
+ "github.com/MichaelMure/git-bug/api/graphql"
+ httpapi "github.com/MichaelMure/git-bug/api/http"
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/identity"
"github.com/MichaelMure/git-bug/repository"
- "github.com/MichaelMure/git-bug/util/git"
"github.com/MichaelMure/git-bug/webui"
)
var (
- webUIPort int
- webUIOpen bool
- webUINoOpen bool
+ webUIPort int
+ webUIOpen bool
+ webUINoOpen bool
+ webUIReadOnly bool
)
const webUIOpenConfigKey = "git-bug.webui.open"
@@ -46,22 +47,31 @@ func runWebUI(cmd *cobra.Command, args []string) error {
router := mux.NewRouter()
- graphqlHandler, err := graphql.NewHandler(repo)
+ // If the webUI is not read-only, use an authentication middleware with a
+ // fixed identity: the default user of the repo
+ // TODO: support dynamic authentication with OAuth
+ if !webUIReadOnly {
+ author, err := identity.GetUserIdentity(repo)
+ if err != nil {
+ return err
+ }
+ router.Use(auth.Middleware(author.Id()))
+ }
+
+ mrc := cache.NewMultiRepoCache()
+ _, err := mrc.RegisterDefaultRepository(repo)
if err != nil {
return err
}
- assetsHandler := &fileSystemWithDefault{
- FileSystem: webui.WebUIAssets,
- defaultFile: "index.html",
- }
+ graphqlHandler := graphql.NewHandler(mrc)
// Routes
router.Path("/playground").Handler(playground.Handler("git-bug", "/graphql"))
router.Path("/graphql").Handler(graphqlHandler)
- router.Path("/gitfile/{hash}").Handler(newGitFileHandler(repo))
- router.Path("/upload").Methods("POST").Handler(newGitUploadFileHandler(repo))
- router.PathPrefix("/").Handler(http.FileServer(assetsHandler))
+ router.Path("/gitfile/{repo}/{hash}").Handler(httpapi.NewGitFileHandler(mrc))
+ router.Path("/upload/{repo}").Methods("POST").Handler(httpapi.NewGitUploadFileHandler(mrc))
+ router.PathPrefix("/").Handler(webui.NewHandler())
srv := &http.Server{
Addr: addr,
@@ -128,119 +138,6 @@ func runWebUI(cmd *cobra.Command, args []string) error {
return nil
}
-// implement a http.FileSystem that will serve a default file when the looked up
-// file doesn't exist. Useful for Single-Page App that implement routing client
-// side, where the server has to return the root index.html file for every route.
-type fileSystemWithDefault struct {
- http.FileSystem
- defaultFile string
-}
-
-func (fswd *fileSystemWithDefault) Open(name string) (http.File, error) {
- f, err := fswd.FileSystem.Open(name)
- if os.IsNotExist(err) {
- return fswd.FileSystem.Open(fswd.defaultFile)
- }
- return f, err
-}
-
-// implement a http.Handler that will read and server git blob.
-type gitFileHandler struct {
- repo repository.Repo
-}
-
-func newGitFileHandler(repo repository.Repo) http.Handler {
- return &gitFileHandler{
- repo: repo,
- }
-}
-
-func (gfh *gitFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- hash := git.Hash(mux.Vars(r)["hash"])
-
- if !hash.IsValid() {
- http.Error(rw, "invalid git hash", http.StatusBadRequest)
- return
- }
-
- // TODO: this mean that the whole file will he buffered in memory
- // This can be a problem for big files. There might be a way around
- // that by implementing a io.ReadSeeker that would read and discard
- // data when a seek is called.
- data, err := gfh.repo.ReadData(git.Hash(hash))
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
-
- http.ServeContent(rw, r, "", time.Now(), bytes.NewReader(data))
-}
-
-// implement a http.Handler that will accept and store content into git blob.
-type gitUploadFileHandler struct {
- repo repository.Repo
-}
-
-func newGitUploadFileHandler(repo repository.Repo) http.Handler {
- return &gitUploadFileHandler{
- repo: repo,
- }
-}
-
-func (gufh *gitUploadFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- // 100MB (github limit)
- var maxUploadSize int64 = 100 * 1000 * 1000
- r.Body = http.MaxBytesReader(rw, r.Body, maxUploadSize)
- if err := r.ParseMultipartForm(maxUploadSize); err != nil {
- http.Error(rw, "file too big (100MB max)", http.StatusBadRequest)
- return
- }
-
- file, _, err := r.FormFile("uploadfile")
- if err != nil {
- http.Error(rw, "invalid file", http.StatusBadRequest)
- return
- }
- defer file.Close()
- fileBytes, err := ioutil.ReadAll(file)
- if err != nil {
- http.Error(rw, "invalid file", http.StatusBadRequest)
- return
- }
-
- filetype := http.DetectContentType(fileBytes)
- if filetype != "image/jpeg" && filetype != "image/jpg" &&
- filetype != "image/gif" && filetype != "image/png" {
- http.Error(rw, "invalid file type", http.StatusBadRequest)
- return
- }
-
- hash, err := gufh.repo.StoreData(fileBytes)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
-
- type response struct {
- Hash string `json:"hash"`
- }
-
- resp := response{Hash: string(hash)}
-
- js, err := json.Marshal(resp)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
-
- rw.Header().Set("Content-Type", "application/json")
- _, err = rw.Write(js)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
-}
-
var webUICmd = &cobra.Command{
Use: "webui",
Short: "Launch the web UI.",
@@ -249,7 +146,7 @@ var webUICmd = &cobra.Command{
Available git config:
git-bug.webui.open [bool]: control the automatic opening of the web UI in the default browser
`,
- PreRunE: loadRepoEnsureUser,
+ PreRunE: loadRepo,
RunE: runWebUI,
}
@@ -261,5 +158,5 @@ func init() {
webUICmd.Flags().BoolVar(&webUIOpen, "open", false, "Automatically open the web UI in the default browser")
webUICmd.Flags().BoolVar(&webUINoOpen, "no-open", false, "Prevent the automatic opening of the web UI in the default browser")
webUICmd.Flags().IntVarP(&webUIPort, "port", "p", 0, "Port to listen to (default is random)")
-
+ webUICmd.Flags().BoolVar(&webUIReadOnly, "read-only", false, "Whether to run the web UI in read-only mode")
}