├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── all.go ├── auth.go ├── buildRoot ├── etc │ ├── bla │ │ ├── config.ini │ │ └── postinstall.sh │ ├── default │ │ └── bla │ └── logrotate.d │ │ └── bla ├── usr │ └── lib │ │ └── systemd │ │ └── system │ │ └── bla.service └── var │ ├── lib │ └── bla │ │ ├── docs │ │ └── hello-world.md │ │ ├── libs │ │ └── css │ │ │ └── base.css │ │ └── template │ │ ├── all.tmpl │ │ ├── doc.tmpl │ │ ├── footer.tmpl │ │ ├── header.tmpl │ │ ├── index.tmpl │ │ ├── root.tmpl │ │ ├── single.tmpl │ │ └── tag.tmpl │ └── log │ └── bla │ └── access.log ├── cmd └── bla │ └── main.go ├── config.go ├── doc.go ├── doc_test.go ├── error.go ├── index.go ├── link.go ├── main.go ├── server.go ├── sitemap.go ├── tags.go ├── tmpl.go └── webdav.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .tmpBuildRoot 3 | pkg 4 | vendor/.cache 5 | self.config.ini 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/github.com/beorn7/perks"] 2 | path = vendor/github.com/beorn7/perks 3 | url = https://github.com/beorn7/perks 4 | [submodule "vendor/github.com/fsnotify/fsnotify"] 5 | path = vendor/github.com/fsnotify/fsnotify 6 | url = https://github.com/fsnotify/fsnotify 7 | [submodule "vendor/github.com/golang/protobuf"] 8 | path = vendor/github.com/golang/protobuf 9 | url = https://github.com/golang/protobuf 10 | [submodule "vendor/github.com/matttproud/golang_protobuf_extensions"] 11 | path = vendor/github.com/matttproud/golang_protobuf_extensions 12 | url = https://github.com/matttproud/golang_protobuf_extensions 13 | [submodule "vendor/github.com/prometheus/client_golang"] 14 | path = vendor/github.com/prometheus/client_golang 15 | url = https://github.com/prometheus/client_golang 16 | [submodule "vendor/github.com/prometheus/client_model"] 17 | path = vendor/github.com/prometheus/client_model 18 | url = https://github.com/prometheus/client_model 19 | [submodule "vendor/github.com/prometheus/common"] 20 | path = vendor/github.com/prometheus/common 21 | url = https://github.com/prometheus/common 22 | [submodule "vendor/github.com/prometheus/procfs"] 23 | path = vendor/github.com/prometheus/procfs 24 | url = https://github.com/prometheus/procfs 25 | [submodule "vendor/github.com/russross/blackfriday"] 26 | path = vendor/github.com/russross/blackfriday 27 | url = https://github.com/russross/blackfriday 28 | [submodule "vendor/github.com/shurcooL/sanitized_anchor_name"] 29 | path = vendor/github.com/shurcooL/sanitized_anchor_name 30 | url = https://github.com/shurcooL/sanitized_anchor_name 31 | [submodule "vendor/golang.org/x/net"] 32 | path = vendor/golang.org/x/net 33 | url = https://go.googlesource.com/net 34 | [submodule "vendor/golang.org/x/sys"] 35 | path = vendor/golang.org/x/sys 36 | url = https://go.googlesource.com/sys 37 | [submodule "vendor/gopkg.in/ini.v1"] 38 | path = vendor/gopkg.in/ini.v1 39 | url = https://gopkg.in/ini.v1 40 | [submodule "vendor/github.com/lucas-clemente/quic-go"] 41 | path = vendor/github.com/lucas-clemente/quic-go 42 | url = https://github.com/lucas-clemente/quic-go 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Meng Zhuo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION := $(shell git describe --tags) 2 | DESTDIR?=.tmpBuildRoot 3 | 4 | .PHONY: binary 5 | binary: clean build 6 | 7 | .PHONY: clean 8 | clean: 9 | rm -rf *.deb 10 | rm -rf *.rpm 11 | rm -rf bla 12 | rm -rf ${DESTDIR} 13 | 14 | .PHONY: build 15 | build: 16 | go build -o bla -ldflags '-X main.Version=${VERSION}' cmd/bla/main.go 17 | 18 | .PHONY: pkg 19 | pkg: 20 | rm -rf ${DESTDIR} 21 | mkdir ${DESTDIR} 22 | cp -rf buildRoot/* ${DESTDIR}/ 23 | mkdir -p ${DESTDIR}/usr/local/bin 24 | mkdir -p ${DESTDIR}/var/log/bla/ 25 | cp bla ${DESTDIR}/usr/local/bin/ 26 | 27 | deb: clean build pkg 28 | fpm -t deb -s dir -n bla -v $(VERSION:v%=%) -C ${DESTDIR} --after-install buildRoot/etc/bla/postinstall.sh 29 | 30 | rpm: clean build pkg 31 | fpm -t rpm -s dir -n bla -v ${VERSION} -C ${DESTDIR} 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bla 2 | 3 | Blog/Lite-CMS build on Automatic static file serving 4 | 5 | ## feature 6 | 7 | * Markdown format, yes! 8 | * Tags and page 9 | * WebDav, no git/svn required 10 | * Automatically build site 11 | * Customable theme and everything 12 | * TLS/SSL ready 13 | 14 | ## TODO 15 | 16 | - [ ] HTTP jump to HTTPs 17 | - [x] RPM/Deb pack 18 | - [ ] default doc generate 19 | - [x] expvar 20 | - [x] service file 21 | - [x] sitemap.txt 22 | - [ ] detail document 23 | -------------------------------------------------------------------------------- /all.go: -------------------------------------------------------------------------------- 1 | package bla 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | func generateAllPage(s *Handler, publicPath string) (err error) { 9 | 10 | f, err := os.Create(filepath.Join(publicPath, "all")) 11 | if err != nil { 12 | return 13 | } 14 | defer f.Close() 15 | 16 | return s.tpl.ExecuteTemplate(f, "all", 17 | &mulDocData{s, "", s.sortDocs}) 18 | } 19 | -------------------------------------------------------------------------------- /auth.go: -------------------------------------------------------------------------------- 1 | package bla 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "net/http" 7 | "strings" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | func fetchIP(ra string) string { 13 | 14 | i := strings.LastIndex(ra, ":") 15 | if i == -1 { 16 | return "unknown" 17 | } 18 | return ra[:i] 19 | } 20 | 21 | type authRateByIPHandler struct { 22 | origin http.Handler 23 | ticker *time.Ticker 24 | record map[string]int 25 | mu sync.RWMutex 26 | 27 | username, password string 28 | limit int 29 | realm string 30 | } 31 | 32 | func NewAuthRateByIPHandler(realm string, origin http.Handler, username, password string, limit int) *authRateByIPHandler { 33 | 34 | ticker := time.NewTicker(time.Minute) 35 | 36 | a := &authRateByIPHandler{origin, 37 | ticker, 38 | map[string]int{}, 39 | sync.RWMutex{}, 40 | 41 | username, 42 | password, 43 | limit, 44 | realm, 45 | } 46 | 47 | go func() { 48 | for { 49 | <-a.ticker.C 50 | a.mu.Lock() 51 | for k, _ := range a.record { 52 | delete(a.record, k) 53 | } 54 | a.mu.Unlock() 55 | } 56 | }() 57 | return a 58 | } 59 | 60 | func (a *authRateByIPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 61 | 62 | ip := fetchIP(r.RemoteAddr) 63 | a.mu.RLock() 64 | rec := a.record[ip] 65 | a.mu.RUnlock() 66 | if rec > a.limit { 67 | fmt.Fprintf(w, "