Exemplo n.º 1
0
func (con Auth) Handler(c context.Context) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		action := webfw.GetMultiPatternIdentifier(c, r)
		sess := webfw.GetSession(c, r)

		var resp responseError

		switch action {
		case "auth-data":
			user := readeef.GetUser(c, r)
			resp = getAuthData(user, sess, con.capabilities)
		case "logout":
			resp = logout(sess)
		}

		var b []byte
		if resp.err == nil {
			b, resp.err = json.Marshal(resp.val)
		}
		if resp.err == nil {
			w.Write(b)
		} else {
			webfw.GetLogger(c).Print(resp.err)

			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	})
}
Exemplo n.º 2
0
func (con Login) Handler(c context.Context) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := webfw.GetLogger(c)
		sess := webfw.GetSession(c, r)
		renderData := renderer.RenderData{}

		if r.Method == "GET" {
			if v, ok := sess.Flash("form-error"); ok {
				renderData["form-error"] = v
			}
		} else {
			if err := r.ParseForm(); err != nil {
				l.Fatal(err)
			}
			username := data.Login(r.Form.Get("username"))
			password := r.Form.Get("password")

			repo := GetRepo(c)
			conf := GetConfig(c)
			u := repo.UserByLogin(username)

			formError := false
			if u.Err() != nil {
				sess.SetFlash("form-error", "login-incorrect")
				formError = true
			} else if !u.Authenticate(password, []byte(conf.Auth.Secret)) {
				sess.SetFlash("form-error", "login-incorrect")
				formError = true
			} else {
				sess.Set(AuthUserKey, u)
				sess.Set(AuthNameKey, username)
			}

			if formError {
				http.Redirect(w, r, r.URL.String(), http.StatusTemporaryRedirect)
			} else {
				var returnPath string
				if v, ok := sess.Flash("return-to"); ok {
					returnPath = v.(string)
				} else {
					returnPath = webfw.GetDispatcher(c).Pattern
				}
				http.Redirect(w, r, returnPath, http.StatusTemporaryRedirect)
			}
			return
		}
		err := webfw.GetRenderCtx(c, r)(w, renderData, "login.tmpl")
		if err != nil {
			l.Print(err)
		}
	}
}
Exemplo n.º 3
0
func (con Login) Handler(c context.Context) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := webfw.GetLogger(c)
		sess := webfw.GetSession(c, r)
		data := renderer.RenderData{}

		if r.Method == "GET" {
			if v, ok := sess.Flash("form-error"); ok {
				data["form-error"] = v
			}
		} else {
			if err := r.ParseForm(); err != nil {
				l.Fatal(err)
			}
			username := r.Form.Get("username")
			password := r.Form.Get("password")

			db := GetDB(c)

			formError := false
			if u, err := db.GetUser(username); err != nil {
				sess.SetFlash("form-error", "login-incorrect")
				formError = true
			} else if !u.Authenticate(password) {
				sess.SetFlash("form-error", "login-incorrect")
				formError = true
			} else {
				sess.Set(authkey, u)
				sess.Set(namekey, u.Login)
			}

			if formError {
				http.Redirect(w, r, r.URL.String(), http.StatusTemporaryRedirect)
			} else {
				var returnPath string
				if v, ok := sess.Flash("return-to"); ok {
					returnPath = v.(string)
				} else {
					returnPath = webfw.GetDispatcher(c).Pattern
				}
				http.Redirect(w, r, returnPath, http.StatusTemporaryRedirect)
			}
			return
		}
		err := webfw.GetRenderCtx(c, r)(w, data, "login.tmpl")
		if err != nil {
			l.Print(err)
		}
	}
}
Exemplo n.º 4
0
func (mw Auth) Handler(ph http.Handler, c context.Context, l *log.Logger) http.Handler {
	handler := func(w http.ResponseWriter, r *http.Request) {
		for _, prefix := range mw.IgnoreURLPrefix {
			if prefix[0] == '/' {
				prefix = prefix[1:]
			}

			if strings.HasPrefix(r.URL.Path, mw.Pattern+prefix+"/") {
				ph.ServeHTTP(w, r)
				return
			}
		}

		route, _, ok := webfw.GetDispatcher(c).RequestRoute(r)
		if !ok {
			ph.ServeHTTP(w, r)
			return
		}

		switch ac := route.Controller.(type) {
		case AuthController:
			if !ac.LoginRequired(c, r) {
				ph.ServeHTTP(w, r)
				return
			}

			sess := webfw.GetSession(c, r)

			var u User
			validUser := false
			if uv, ok := sess.Get(authkey); ok {
				if u, ok = uv.(User); ok {
					validUser = true
				}
			}

			if !validUser {
				if uv, ok := sess.Get(namekey); ok {
					if n, ok := uv.(string); ok {
						var err error
						u, err = mw.DB.GetUser(n)

						if err == nil {
							validUser = true
							sess.Set(authkey, u)
						} else if _, ok := err.(ValidationError); !ok {
							l.Print(err)
						}
					}
				}
			}

			if validUser && !u.Active {
				Debug.Println("User " + u.Login + " is inactive")
				validUser = false
			}

			if !validUser {
				d := webfw.GetDispatcher(c)
				sess.SetFlash(CtxKey("return-to"), r.URL.Path)
				path := d.NameToPath("auth-login", webfw.MethodGet)

				if path == "" {
					path = "/"
				}

				http.Redirect(w, r, path, http.StatusMovedPermanently)
				return
			}

		case ApiAuthController:
			if !ac.AuthRequired(c, r) {
				ph.ServeHTTP(w, r)
				return
			}

			var u User
			var err error

			auth := r.Header.Get("Authorization")
			validUser := false

			if auth != "" {
				switch {
				default:
					if !strings.HasPrefix(auth, "Readeef ") {
						break
					}
					auth = auth[len("Readeef "):]

					parts := strings.SplitN(auth, ":", 2)
					login := parts[0]

					u, err = mw.DB.GetUser(login)
					if err != nil {
						l.Printf("Error getting db user '%s': %v\n", login, err)
						break
					}

					var decoded []byte
					decoded, err = base64.StdEncoding.DecodeString(parts[1])
					if err != nil {
						l.Printf("Error decoding auth header: %v\n", err)
						break
					}

					date := r.Header.Get("X-Date")
					t, err := time.Parse(http.TimeFormat, date)
					if err != nil || t.Add(30*time.Second).Before(time.Now()) {
						break
					}

					nonce := r.Header.Get("X-Nonce")
					if !mw.Nonce.Check(nonce) {
						break
					}
					mw.Nonce.Remove(nonce)

					buf := util.BufferPool.GetBuffer()
					defer util.BufferPool.Put(buf)

					buf.ReadFrom(r.Body)
					r.Body = ioutil.NopCloser(buf)

					bodyHash := md5.New()
					if _, err := bodyHash.Write(buf.Bytes()); err != nil {
						l.Printf("Error generating the hash for the request body: %v\n", err)
						break
					}

					contentMD5 := base64.StdEncoding.EncodeToString(bodyHash.Sum(nil))

					message := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n",
						r.RequestURI, r.Method, contentMD5, r.Header.Get("Content-Type"),
						date, nonce)

					b := make([]byte, base64.StdEncoding.EncodedLen(len(u.MD5API)))
					base64.StdEncoding.Encode(b, u.MD5API)

					hm := hmac.New(sha256.New, b)
					if _, err := hm.Write([]byte(message)); err != nil {
						l.Printf("Error generating the hashed message: %v\n", err)
						break
					}

					if !hmac.Equal(hm.Sum(nil), decoded) {
						l.Printf("Error matching the supplied auth message to the generated one.\n")
						break
					}

					if !u.Active {
						Debug.Println("User " + u.Login + " is inactive")
						break
					}

					validUser = true
				}
			}

			if !validUser {
				w.WriteHeader(http.StatusForbidden)
				return
			}

			c.Set(r, context.BaseCtxKey("user"), u)
		}

		ph.ServeHTTP(w, r)
	}

	return http.HandlerFunc(handler)
}
Exemplo n.º 5
0
func (con WebSocket) Handler(c context.Context) http.Handler {
	var mutex sync.RWMutex

	receivers := make(map[chan content.Feed]bool)
	logger := webfw.GetLogger(c)

	go func() {
		for {
			select {
			case feed := <-con.updateFeed:
				logger.Infoln("New articles notification for " + feed.String())
				mutex.RLock()

				for receiver, _ := range receivers {
					receiver <- feed
				}

				mutex.RUnlock()
			}
		}
	}()

	cfg := readeef.GetConfig(c)
	return websocket.Handler(func(ws *websocket.Conn) {
		user := readeef.GetUser(c, ws.Request())
		sess := webfw.GetSession(c, ws.Request())

		msg := make(chan apiRequest)
		resp := make(chan apiResponse)

		receiver := make(chan content.Feed)

		mutex.Lock()
		receivers[receiver] = true
		mutex.Unlock()
		defer func() {
			mutex.Lock()
			close(receiver)
			delete(receivers, receiver)
			mutex.Unlock()
		}()

		go func() {
			for {
				var r responseError

				select {
				case data := <-msg:
					var err error
					var processor Processor

					if processor, err = data.processor(c, sess, user, con.fm, con.sp, con.extractor,
						con.capabilities, []byte(cfg.Auth.Secret)); err == nil {
						if len(data.Arguments) > 0 {
							err = json.Unmarshal([]byte(data.Arguments), processor)
						}

						if err == nil {
							r = processor.Process()
						}
					}

					if err != nil {
						r.err = err
						switch err.(type) {
						case *json.UnmarshalTypeError:
							r.errType = errTypeInvalidArgValue
						default:
							if err == errInvalidMethodValue {
								r.errType = errTypeInvalidMethodValue
							} else if err == content.ErrNoContent {
								r.err = errResourceNotFound
								r.errType = errTypeResourceNotFound
							}
						}
					}

					go func() {
						var err string
						if r.err != nil {
							err = r.err.Error()
						}
						resp <- apiResponse{
							Success: r.err == nil, Error: err, ErrorType: r.errType,
							Method: data.Method, Tag: data.Tag, Arguments: r.val,
						}
					}()
				case f := <-receiver:
					if f == nil || user == nil {
						// Socket was closed
						return
					}
					logger.Infoln("Received notification for feed update of " + f.String())

					r := newResponse()

					uf := user.FeedById(f.Data().Id)

					if !uf.HasErr() {
						r.val["Feed"] = uf

						go func() {
							var err string
							if r.err != nil {
								err = r.err.Error()
							}
							resp <- apiResponse{
								Success: r.err == nil, Error: err, ErrorType: r.errType,
								Method: "feed-update-notifier", Tag: "", Arguments: r.val,
							}
						}()
					}
				case r := <-resp:
					websocket.JSON.Send(ws, r)
				}
			}
		}()

		for {
			var data apiRequest
			if err := websocket.JSON.Receive(ws, &data); err != nil {
				if err == io.EOF {
					// Websocket was closed
					break
				} else {
					websocket.JSON.Send(ws, apiResponse{
						Success: false, ErrorType: errTypeMessageParse,
						Error: err.Error(), Method: data.Method,
					})
				}
			}

			if forbidden(c, ws.Request()) {
				websocket.JSON.Send(ws, apiResponse{
					Success: false, ErrorType: errTypeUnauthorized,
					Error: errUnauthorized.Error(), Method: data.Method,
				})
				break
			}

			msg <- data
		}

		logger.Infoln("Closing web socket")
	})
}
Exemplo n.º 6
0
func (con Proxy) Handler(c context.Context) http.Handler {
	logger := webfw.GetLogger(c)
	config := readeef.GetConfig(c)
	client := readeef.NewTimeoutClient(config.Timeout.Converted.Connect, config.Timeout.Converted.ReadWrite)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sess := webfw.GetSession(c, r)

		if _, ok := sess.Get(readeef.AuthNameKey); !ok {
			w.WriteHeader(http.StatusForbidden)
			return
		}

		if r.Method == "HEAD" {
			return
		}

		r.ParseForm()
		var err error

		switch {
		default:
			var u *url.URL

			u, err = url.Parse(r.Form.Get("url"))
			if err != nil {
				err = fmt.Errorf("Error parsing url to proxy (%s): %v", r.Form.Get("url"), err)
				break
			}
			if u.Scheme == "" {
				u.Scheme = "http"
			}

			var req *http.Request

			req, err = http.NewRequest("GET", u.String(), nil)
			if err != nil {
				err = fmt.Errorf("Error creating proxy request to %s: %v", u, err)
				break
			}

			var resp *http.Response

			resp, err = client.Do(req)
			if err != nil {
				err = fmt.Errorf("Error getting proxy response from %s: %v", u, err)
				break
			}

			defer resp.Body.Close()

			for k, values := range resp.Header {
				for _, v := range values {
					w.Header().Add(k, v)
				}
			}

			var b []byte

			b, err = ioutil.ReadAll(resp.Body)
			if err != nil {
				err = fmt.Errorf("Error reading proxy response from %s: %v", u, err)
				break
			}

			_, err = w.Write(b)
		}

		if err != nil {
			logger.Infoln(err)
			w.WriteHeader(http.StatusNotAcceptable)
			return
		}

		return
	})
}
Exemplo n.º 7
0
func (imw I18N) Handler(ph http.Handler, c context.Context) http.Handler {
	for _, l := range imw.Languages {
		file, err := fs.DefaultFS.OpenRoot(imw.Dir, l+".all.json")
		if err == nil {
			var b []byte

			if b, err = ioutil.ReadAll(file); err == nil {
				err = i18n.ParseTranslationFileBytes(l+".all.json", b)
			}
		}

		if err != nil {
			panic(fmt.Sprintf("Error opening locale file '%s.all.json': %v\n", l, err))
		}
	}

	renderer := webfw.GetRenderer(c)
	renderer.Funcs(imw.TemplateFuncMap())

	handler := func(w http.ResponseWriter, r *http.Request) {
		c.Set(r, context.BaseCtxKey("langs"), imw.Languages)

		if len(imw.Languages) == 0 {
			c.Set(r, context.BaseCtxKey("lang"), "")
			ph.ServeHTTP(w, r)
			return
		}

		found := false

		uriParts := strings.SplitN(r.RequestURI, "?", 2)
		if uriParts[0] == "" {
			uriParts[0] = r.URL.Path
		}
		for _, prefix := range imw.IgnoreURLPrefix {
			if prefix[0] == '/' {
				prefix = prefix[1:]
			}

			if strings.HasPrefix(uriParts[0], imw.Pattern+prefix+"/") {
				found = true
				break
			}

			if uriParts[0] == imw.Pattern+prefix {
				found = true
				break
			}
		}

		if !found {
			for _, language := range imw.Languages {
				if uriParts[0] == imw.Pattern+language {
					url := uriParts[0] + "/"
					if len(uriParts) > 1 && uriParts[1] != "" {
						url += "?" + uriParts[1]
					}

					http.Redirect(w, r, url, http.StatusFound)

					return
				}

				if strings.HasPrefix(uriParts[0], imw.Pattern+language+"/") {
					r.URL.Path = imw.Pattern + r.URL.Path[len(imw.Pattern+language+"/"):]

					uriParts[0] = imw.Pattern + uriParts[0][len(imw.Pattern+language+"/"):]

					r.RequestURI = strings.Join(uriParts, "?")

					c.Set(r, context.BaseCtxKey("lang"), language)
					found = true

					s := webfw.GetSession(c, r)
					s.Set("language", language)

					break
				}
			}
		}

		if !found {
			fallback := webfw.GetFallbackLanguage(c, r, imw.FallbackLanguage)
			index := strings.Index(fallback, "-")
			short := fallback
			if index > -1 {
				short = fallback[:index]
			}
			foundShort := false

			for _, language := range imw.Languages {
				if language == fallback {
					found = true
					break
				}

				if language == short {
					foundShort = true
				}
			}

			var language string
			if found {
				language = fallback
			} else if foundShort {
				language = short
			} else {
				language = imw.FallbackLanguage
			}

			url := imw.Pattern + language + uriParts[0][len(imw.Pattern)-1:]
			if len(uriParts) > 1 && uriParts[1] != "" {
				url += "?" + uriParts[1]
			}

			http.Redirect(w, r, url, http.StatusFound)

			return
		}

		ph.ServeHTTP(w, r)
	}

	return http.HandlerFunc(handler)
}
Exemplo n.º 8
0
func (mw Auth) Handler(ph http.Handler, c context.Context) http.Handler {
	logger := webfw.GetLogger(c)
	handler := func(w http.ResponseWriter, r *http.Request) {
		for _, prefix := range mw.IgnoreURLPrefix {
			if prefix[0] == '/' {
				prefix = prefix[1:]
			}

			if strings.HasPrefix(r.URL.Path, mw.Pattern+prefix+"/") {
				ph.ServeHTTP(w, r)
				return
			}
		}

		route, _, ok := webfw.GetDispatcher(c).RequestRoute(r)
		if !ok {
			ph.ServeHTTP(w, r)
			return
		}

		repo := GetRepo(c)

		switch ac := route.Controller.(type) {
		case AuthController:
			if !ac.LoginRequired(c, r) {
				ph.ServeHTTP(w, r)
				return
			}

			sess := webfw.GetSession(c, r)

			var u content.User
			validUser := false
			if uv, ok := sess.Get(AuthUserKey); ok {
				if u, ok = uv.(content.User); ok {
					validUser = true
				}
			}

			if !validUser {
				if uv, ok := sess.Get(AuthNameKey); ok {
					if n, ok := uv.(data.Login); ok {
						u = repo.UserByLogin(n)

						if u.HasErr() {
							logger.Print(u.Err())
						} else {
							validUser = true
							sess.Set(AuthUserKey, u)
						}
					}
				}
			}

			if validUser && !u.Data().Active {
				logger.Infoln("User " + u.Data().Login + " is inactive")
				validUser = false
			}

			if !validUser {
				d := webfw.GetDispatcher(c)
				sess.SetFlash(CtxKey("return-to"), r.URL.Path)
				path := d.NameToPath("auth-login", webfw.MethodGet)

				if path == "" {
					path = "/"
				}

				http.Redirect(w, r, path, http.StatusMovedPermanently)
				return
			}

		case ApiAuthController:
			if !ac.AuthRequired(c, r) {
				ph.ServeHTTP(w, r)
				return
			}

			url, login, signature, nonce, date, t := authData(r)

			validUser := false

			var u content.User

			if login != "" && signature != "" && !t.IsZero() {
				switch {
				default:
					u = repo.UserByLogin(data.Login(login))
					if u.HasErr() {
						logger.Printf("Error getting db user '%s': %v\n", login, u.Err())
						break
					}

					decoded, err := base64.StdEncoding.DecodeString(signature)
					if err != nil {
						logger.Printf("Error decoding auth header: %v\n", err)
						break
					}

					if t.Add(30 * time.Second).Before(time.Now()) {
						break
					}

					if !mw.Nonce.Check(nonce) {
						break
					}
					mw.Nonce.Remove(nonce)

					buf := util.BufferPool.GetBuffer()
					defer util.BufferPool.Put(buf)

					buf.ReadFrom(r.Body)
					r.Body = ioutil.NopCloser(buf)

					bodyHash := md5.New()
					if _, err := bodyHash.Write(buf.Bytes()); err != nil {
						logger.Printf("Error generating the hash for the request body: %v\n", err)
						break
					}

					contentMD5 := base64.StdEncoding.EncodeToString(bodyHash.Sum(nil))

					message := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n",
						url, r.Method, contentMD5, r.Header.Get("Content-Type"),
						date, nonce)

					b := make([]byte, base64.StdEncoding.EncodedLen(len(u.Data().MD5API)))
					base64.StdEncoding.Encode(b, u.Data().MD5API)

					hm := hmac.New(sha256.New, b)
					if _, err := hm.Write([]byte(message)); err != nil {
						logger.Printf("Error generating the hashed message: %v\n", err)
						break
					}

					if !hmac.Equal(hm.Sum(nil), decoded) {
						logger.Printf("Error matching the supplied auth message to the generated one.\n")
						break
					}

					if !u.Data().Active {
						logger.Println("User " + u.Data().Login + " is inactive")
						break
					}

					validUser = true
				}
			}

			if validUser {
				c.Set(r, context.BaseCtxKey("user"), u)
			} else {
				if rej, ok := ac.(AuthRejectHandler); ok {
					rej.AuthReject(c, r)
				} else {
					w.WriteHeader(http.StatusUnauthorized)
					return
				}
			}
		}

		ph.ServeHTTP(w, r)
	}

	return http.HandlerFunc(handler)
}