WIP: move auth to web
ci/woodpecker/pr/docs Pipeline was successful
Details
ci/woodpecker/pr/lint Pipeline was successful
Details
ci/woodpecker/pr/build Pipeline was successful
Details
ci/woodpecker/pr/docker Pipeline was successful
Details
ci/woodpecker/pr/man Pipeline was successful
Details
ci/woodpecker/pr/test Pipeline was successful
Details
ci/woodpecker/pr/docs Pipeline was successful
Details
ci/woodpecker/pr/lint Pipeline was successful
Details
ci/woodpecker/pr/build Pipeline was successful
Details
ci/woodpecker/pr/docker Pipeline was successful
Details
ci/woodpecker/pr/man Pipeline was successful
Details
ci/woodpecker/pr/test Pipeline was successful
Details
parent
9268ef0302
commit
fc5650fe78
|
@ -12,12 +12,8 @@ import models { BuildLog, BuildLogFilter }
|
||||||
|
|
||||||
// v1_get_logs returns all build logs in the database. A 'target' query param can
|
// v1_get_logs returns all build logs in the database. A 'target' query param can
|
||||||
// optionally be added to limit the list of build logs to that repository.
|
// optionally be added to limit the list of build logs to that repository.
|
||||||
['/api/v1/logs'; get]
|
['/api/v1/logs'; auth; get]
|
||||||
fn (mut app App) v1_get_logs() web.Result {
|
fn (mut app App) v1_get_logs() web.Result {
|
||||||
if !app.is_authorized() {
|
|
||||||
return app.json(http.Status.unauthorized, new_response('Unauthorized.'))
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := models.from_params<BuildLogFilter>(app.query) or {
|
filter := models.from_params<BuildLogFilter>(app.query) or {
|
||||||
return app.json(http.Status.bad_request, new_response('Invalid query parameters.'))
|
return app.json(http.Status.bad_request, new_response('Invalid query parameters.'))
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ pub fn server(conf Config) ? {
|
||||||
|
|
||||||
web.run(&App{
|
web.run(&App{
|
||||||
logger: logger
|
logger: logger
|
||||||
|
api_key: conf.api_key
|
||||||
conf: conf
|
conf: conf
|
||||||
repo: repo
|
repo: repo
|
||||||
db: db
|
db: db
|
||||||
|
|
|
@ -26,6 +26,14 @@ pub const (
|
||||||
value: 'text/plain'
|
value: 'text/plain'
|
||||||
).join(headers_close)
|
).join(headers_close)
|
||||||
)
|
)
|
||||||
|
http_401 = http.new_response(
|
||||||
|
status: .unauthorized
|
||||||
|
body: '401 Unauthorized'
|
||||||
|
header: http.new_header(
|
||||||
|
key: .content_type
|
||||||
|
value: 'text/plain'
|
||||||
|
).join(headers_close)
|
||||||
|
)
|
||||||
http_404 = http.new_response(
|
http_404 = http.new_response(
|
||||||
status: .not_found
|
status: .not_found
|
||||||
body: '404 Not Found'
|
body: '404 Not Found'
|
||||||
|
|
|
@ -3,6 +3,10 @@ module web
|
||||||
import net.urllib
|
import net.urllib
|
||||||
import net.http
|
import net.http
|
||||||
|
|
||||||
|
// Method attributes that should be ignored when parsing, as they're using
|
||||||
|
// elsewhere.
|
||||||
|
const attrs_to_ignore = ['auth']
|
||||||
|
|
||||||
// Parsing function attributes for methods and path.
|
// Parsing function attributes for methods and path.
|
||||||
fn parse_attrs(name string, attrs []string) ?([]http.Method, string) {
|
fn parse_attrs(name string, attrs []string) ?([]http.Method, string) {
|
||||||
if attrs.len == 0 {
|
if attrs.len == 0 {
|
||||||
|
@ -32,7 +36,7 @@ fn parse_attrs(name string, attrs []string) ?([]http.Method, string) {
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if x.len > 0 {
|
if x.len > 0 && x.any(!web.attrs_to_ignore.contains(it)) {
|
||||||
return IError(http.UnexpectedExtraAttributeError{
|
return IError(http.UnexpectedExtraAttributeError{
|
||||||
attributes: x
|
attributes: x
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,6 +15,8 @@ import log
|
||||||
// The Context struct represents the Context which hold the HTTP request and response.
|
// The Context struct represents the Context which hold the HTTP request and response.
|
||||||
// It has fields for the query, form, files.
|
// It has fields for the query, form, files.
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
// API key used when authenticating requests
|
||||||
|
api_key string
|
||||||
pub:
|
pub:
|
||||||
// HTTP Request
|
// HTTP Request
|
||||||
req http.Request
|
req http.Request
|
||||||
|
@ -133,6 +135,17 @@ pub fn (mut ctx Context) send_reader_response(mut reader io.Reader, size u64) bo
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_authenticated checks whether the request passes a correct API key.
|
||||||
|
pub fn (ctx &Context) is_authenticated() bool {
|
||||||
|
if provided_key := ctx.req.header.get_custom('X-Api-Key') {
|
||||||
|
println(provided_key)
|
||||||
|
println(ctx.api_key)
|
||||||
|
return provided_key == ctx.api_key
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// json<T> HTTP_OK with json_s as payload with content-type `application/json`
|
// json<T> HTTP_OK with json_s as payload with content-type `application/json`
|
||||||
pub fn (mut ctx Context) json<T>(status http.Status, j T) Result {
|
pub fn (mut ctx Context) json<T>(status http.Status, j T) Result {
|
||||||
ctx.status = status
|
ctx.status = status
|
||||||
|
@ -177,9 +190,12 @@ pub fn (mut ctx Context) file(f_path string) Result {
|
||||||
file.close()
|
file.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Currently, this only supports a single provided range, e.g.
|
||||||
|
// bytes=0-1023, and not multiple ranges, e.g. bytes=0-50, 100-150
|
||||||
if range_str := ctx.req.header.get(.range) {
|
if range_str := ctx.req.header.get(.range) {
|
||||||
mut parts := range_str.split_nth('=', 2)
|
mut parts := range_str.split_nth('=', 2)
|
||||||
|
|
||||||
|
// We only support the 'bytes' range type
|
||||||
if parts[0] != 'bytes' {
|
if parts[0] != 'bytes' {
|
||||||
ctx.status = .requested_range_not_satisfiable
|
ctx.status = .requested_range_not_satisfiable
|
||||||
ctx.header.delete(.content_length)
|
ctx.header.delete(.content_length)
|
||||||
|
@ -394,31 +410,26 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) {
|
||||||
// Used for route matching
|
// Used for route matching
|
||||||
route_words := route.path.split('/').filter(it != '')
|
route_words := route.path.split('/').filter(it != '')
|
||||||
|
|
||||||
// Route immediate matches first
|
// Route immediate matches & index files first
|
||||||
// For example URL `/register` matches route `/:user`, but `fn register()`
|
// For example URL `/register` matches route `/:user`, but `fn register()`
|
||||||
// should be called first.
|
// should be called first.
|
||||||
if !route.path.contains('/:') && url_words == route_words {
|
if (!route.path.contains('/:') && url_words == route_words)
|
||||||
// We found a match
|
|| (url_words.len == 0 && route_words == ['index'] && method.name == 'index') {
|
||||||
if head.method == .post && method.args.len > 0 {
|
// Check whether the request is authorised
|
||||||
// TODO implement POST requests
|
if 'auth' in method.attrs && !app.is_authenticated() {
|
||||||
// Populate method args with form values
|
conn.write(http_401.bytes()) or {}
|
||||||
// mut args := []string{cap: method.args.len}
|
return
|
||||||
// for param in method.args {
|
|
||||||
// args << form[param.name]
|
|
||||||
// }
|
|
||||||
// app.$method(args)
|
|
||||||
} else {
|
|
||||||
app.$method()
|
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if url_words.len == 0 && route_words == ['index'] && method.name == 'index' {
|
// We found a match
|
||||||
app.$method()
|
app.$method()
|
||||||
return
|
} else if params := route_matches(url_words, route_words) {
|
||||||
}
|
// Check whether the request is authorised
|
||||||
|
if 'auth' in method.attrs && !app.is_authenticated() {
|
||||||
|
conn.write(http_401.bytes()) or {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if params := route_matches(url_words, route_words) {
|
|
||||||
method_args := params.clone()
|
method_args := params.clone()
|
||||||
if method_args.len != method.args.len {
|
if method_args.len != method.args.len {
|
||||||
eprintln('warning: uneven parameters count ($method.args.len) in `$method.name`, compared to the web route `$method.attrs` ($method_args.len)')
|
eprintln('warning: uneven parameters count ($method.args.len) in `$method.name`, compared to the web route `$method.attrs` ($method_args.len)')
|
||||||
|
|
Loading…
Reference in New Issue