Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,8 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.v]
|
||||
indent_style = tab
|
||||
@@ -0,0 +1,4 @@
|
||||
*.v linguist-language=V text=auto eol=lf
|
||||
*.vv linguist-language=V text=auto eol=lf
|
||||
*.vsh linguist-language=V text=auto eol=lf
|
||||
**/v.mod linguist-language=V text=auto eol=lf
|
||||
@@ -0,0 +1,11 @@
|
||||
# Binaries for programs and plugins
|
||||
main
|
||||
v
|
||||
*.exe
|
||||
*.exe~
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
vls.log
|
||||
.env
|
||||
*.db
|
||||
@@ -0,0 +1,19 @@
|
||||
module main
|
||||
|
||||
import veb
|
||||
import json
|
||||
|
||||
@['/auth/login'; post]
|
||||
pub fn (mut app App) controller_auth(mut ctx Context) veb.Result {
|
||||
body := json.decode(AuthRequestDto, ctx.req.data) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('Failed to decode json, error: ${err}')
|
||||
}
|
||||
|
||||
response := app.service_auth(body.username, body.password) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('error: ${err}')
|
||||
}
|
||||
|
||||
return ctx.json(response)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module main
|
||||
|
||||
struct AuthRequestDto {
|
||||
// Adding a @[required] attribute will make decoding fail, if that field is not present in the input.
|
||||
// If a field is not [required], but is missing, it will be assumed to have its default value, like 0 for numbers, or '' for strings, and decoding will not fail.
|
||||
username string @[required]
|
||||
password string @[required]
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
module main
|
||||
|
||||
import crypto.hmac
|
||||
import crypto.sha256
|
||||
import crypto.bcrypt
|
||||
import encoding.base64
|
||||
import json
|
||||
import databases
|
||||
import time
|
||||
import os
|
||||
|
||||
struct JwtHeader {
|
||||
alg string
|
||||
typ string
|
||||
}
|
||||
|
||||
struct JwtPayload {
|
||||
sub string // (subject) = Entity to whom the token belongs, usually the user ID;
|
||||
iss string // (issuer) = Token issuer;
|
||||
exp string // (expiration) = Timestamp of when the token will expire;
|
||||
iat time.Time // (issued at) = Timestamp of when the token was created;
|
||||
aud string // (audience) = Token recipient, represents the application that will use it.
|
||||
name string
|
||||
roles string
|
||||
permissions string
|
||||
}
|
||||
|
||||
fn (mut app App) service_auth(username string, password string) !string {
|
||||
mut db := databases.create_db_connection() or {
|
||||
eprintln(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
users := sql db {
|
||||
select from User where username == username
|
||||
}!
|
||||
|
||||
if users.len == 0 {
|
||||
return error('user not found')
|
||||
}
|
||||
|
||||
user := users.first()
|
||||
if !user.active {
|
||||
return error('user is not active')
|
||||
}
|
||||
|
||||
db.close()!
|
||||
|
||||
bcrypt.compare_hash_and_password(password.bytes(), user.password.bytes()) or {
|
||||
return error('Failed to auth user, ${err}')
|
||||
}
|
||||
|
||||
token := make_token(user)
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
fn make_token(user User) string {
|
||||
secret := os.getenv('SECRET_KEY')
|
||||
|
||||
jwt_header := JwtHeader{'HS256', 'JWT'}
|
||||
jwt_payload := JwtPayload{
|
||||
sub: '${user.id}'
|
||||
name: '${user.username}'
|
||||
iat: time.now()
|
||||
}
|
||||
|
||||
header := base64.url_encode(json.encode(jwt_header).bytes())
|
||||
payload := base64.url_encode(json.encode(jwt_payload).bytes())
|
||||
signature := base64.url_encode(hmac.new(secret.bytes(), '${header}.${payload}'.bytes(),
|
||||
sha256.sum, sha256.block_size).bytestr().bytes())
|
||||
|
||||
jwt := '${header}.${payload}.${signature}'
|
||||
|
||||
return jwt
|
||||
}
|
||||
|
||||
fn auth_verify(token string) bool {
|
||||
if token == '' {
|
||||
return false
|
||||
}
|
||||
secret := os.getenv('SECRET_KEY')
|
||||
token_split := token.split('.')
|
||||
|
||||
signature_mirror := hmac.new(secret.bytes(), '${token_split[0]}.${token_split[1]}'.bytes(),
|
||||
sha256.sum, sha256.block_size).bytestr().bytes()
|
||||
|
||||
signature_from_token := base64.url_decode(token_split[2])
|
||||
|
||||
return hmac.equal(signature_from_token, signature_mirror)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module databases
|
||||
|
||||
import db.sqlite
|
||||
|
||||
pub fn create_db_connection() !sqlite.DB {
|
||||
mut db := sqlite.connect('database.db')!
|
||||
return db
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
module main
|
||||
|
||||
import veb
|
||||
import databases
|
||||
|
||||
const http_port = 8081
|
||||
|
||||
pub struct Context {
|
||||
veb.Context
|
||||
}
|
||||
|
||||
struct App {
|
||||
veb.StaticHandler
|
||||
}
|
||||
|
||||
pub fn (app &App) before_request(mut ctx Context) {
|
||||
println('[veb] ${ctx.req.method} ${ctx.req.url}')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut db := databases.create_db_connection() or { panic(err) }
|
||||
|
||||
sql db {
|
||||
create table User
|
||||
} or { panic('error on create table: ${err}') }
|
||||
|
||||
db.close() or { panic(err) }
|
||||
|
||||
mut app := &App{}
|
||||
veb.run[App, Context](mut app, http_port)
|
||||
}
|
||||
|
||||
@['/'; get]
|
||||
pub fn (mut app App) ping(mut ctx Context) veb.Result {
|
||||
return ctx.text('ping')
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
module main
|
||||
|
||||
import veb
|
||||
import json
|
||||
import databases
|
||||
|
||||
@['/user/:id/get'; get]
|
||||
pub fn (mut app App) controller_get_user_by_id(mut ctx Context, id string) veb.Result {
|
||||
response := app.service_get_user_by_id(id.int()) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('${err}')
|
||||
}
|
||||
return ctx.json(response)
|
||||
}
|
||||
|
||||
@['/user/create'; post]
|
||||
pub fn (mut app App) controller_create_user(mut ctx Context) veb.Result {
|
||||
body := json.decode(User, ctx.req.data) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('Failed to decode json, error: ${err}')
|
||||
}
|
||||
|
||||
response := app.service_add_user(body.username, body.password) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('error: ${err}')
|
||||
}
|
||||
|
||||
return ctx.json(response)
|
||||
}
|
||||
|
||||
@['/user/get_all'; get]
|
||||
pub fn (mut app App) controller_get_all_user(mut ctx Context) veb.Result {
|
||||
token := ctx.req.header.get_custom('token') or { '' }
|
||||
|
||||
if !auth_verify(token) {
|
||||
ctx.res.set_status(.unauthorized)
|
||||
return ctx.text('Not valid token')
|
||||
}
|
||||
|
||||
response := app.service_get_all_user() or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('${err}')
|
||||
}
|
||||
return ctx.json(response)
|
||||
}
|
||||
|
||||
@['/user/get_by_username/:username'; get]
|
||||
pub fn (mut app App) controller_get_by_username(mut ctx Context, username string) veb.Result {
|
||||
response := app.service_get_by_username(username) or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('${err}')
|
||||
}
|
||||
return ctx.json(response)
|
||||
}
|
||||
|
||||
@['/user/drop'; delete]
|
||||
pub fn (mut app App) delete(mut ctx Context) veb.Result {
|
||||
mut db := databases.create_db_connection() or {
|
||||
ctx.res.set_status(.bad_request)
|
||||
return ctx.text('${err}')
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
|
||||
sql db {
|
||||
drop table User
|
||||
} or { panic(err) }
|
||||
|
||||
return ctx.text('Successfully deleted table')
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module main
|
||||
|
||||
@[table: 'users']
|
||||
struct User {
|
||||
mut:
|
||||
id int @[primary; sql: serial]
|
||||
username string @[required; sql_type: 'TEXT']
|
||||
password string @[required; sql_type: 'TEXT']
|
||||
created_at string @[default: 'CURRENT_TIMESTAMP']
|
||||
updated_at string @[default: 'CURRENT_TIMESTAMP']
|
||||
deleted_at string @[default: 'CURRENT_TIMESTAMP']
|
||||
active bool
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
module main
|
||||
|
||||
import crypto.bcrypt
|
||||
import databases
|
||||
|
||||
fn (mut app App) service_add_user(username string, password string) !User {
|
||||
mut db := databases.create_db_connection() or {
|
||||
eprintln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
|
||||
hashed_password := bcrypt.generate_from_password(password.bytes(), bcrypt.min_cost) or {
|
||||
eprintln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
user_model := User{
|
||||
username: username
|
||||
password: hashed_password
|
||||
active: true
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert user_model into User
|
||||
} or {
|
||||
eprintln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
users := sql db {
|
||||
select from User where username == username limit 1
|
||||
}!
|
||||
|
||||
return users.first()
|
||||
}
|
||||
|
||||
fn (mut app App) service_get_user_by_id(user_id int) !User {
|
||||
mut db := databases.create_db_connection() or {
|
||||
println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
|
||||
users := sql db {
|
||||
select from User where id == user_id
|
||||
}!
|
||||
|
||||
return users.first()
|
||||
}
|
||||
|
||||
fn (mut app App) service_get_all_user() ![]User {
|
||||
mut db := databases.create_db_connection() or {
|
||||
println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
|
||||
results := sql db {
|
||||
select from User
|
||||
}!
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fn (mut app App) service_get_by_username(username string) !User {
|
||||
mut db := databases.create_db_connection() or {
|
||||
println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
|
||||
results := sql db {
|
||||
select from User where username == username
|
||||
}!
|
||||
|
||||
if results.len == 0 {
|
||||
return error('User not found')
|
||||
}
|
||||
|
||||
return results[0]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
Module {
|
||||
name: 'veb_orm_jwt'
|
||||
description: ''
|
||||
version: ''
|
||||
license: ''
|
||||
dependencies: []
|
||||
}
|
||||
Reference in new issue
Block a user