Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Rémi PAILHAREY
cyber-signal
Commits
0c8be407
Commit
0c8be407
authored
May 17, 2021
by
Rémi PAILHAREY
Browse files
Authentification completed + enhance navbar
parent
6b027467
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
internal/auth/auth.go
View file @
0c8be407
...
...
@@ -2,7 +2,6 @@ package auth
import
(
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
...
...
@@ -74,7 +73,6 @@ func ValidateAuthMiddleware(next http.Handler, allowedRoles []string, checkXSRF
user
:=
TokenData
{}
checkXSRF
,
err
:=
tokens
.
Manager
.
ExtractAndValidateToken
(
r
,
authTokenKey
,
&
user
,
checkXSRF
)
if
err
!=
nil
{
log
.
Logger
.
Println
(
"ERREUR EXTRACTION"
)
// Handle CORS preflight requests
if
r
.
Method
==
"OPTIONS"
{
return
...
...
@@ -102,9 +100,6 @@ func ValidateAuthMiddleware(next http.Handler, allowedRoles []string, checkXSRF
http
.
Error
(
w
,
"XSRF protection triggered"
,
http
.
StatusUnauthorized
)
return
}
if
checkXSRF
&&
r
.
Header
.
Get
(
"XSRF-TOKEN"
)
==
user
.
XSRFToken
{
log
.
Logger
.
Println
(
"token xsrf validé"
)
}
err
=
checkUserHasRole
(
user
,
allowedRoles
)
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusForbidden
)
...
...
@@ -213,7 +208,7 @@ func GetShareToken(w http.ResponseWriter, r *http.Request) {
fmt
.
Fprint
(
w
,
token
)
}
// GetTokenData gets a
n
user from a request
// GetTokenData gets a user from a request
func
GetTokenData
(
r
*
http
.
Request
)
(
TokenData
,
error
)
{
user
,
ok
:=
r
.
Context
()
.
Value
(
ContextData
)
.
(
TokenData
)
if
!
ok
{
...
...
@@ -221,21 +216,3 @@ func GetTokenData(r *http.Request) (TokenData, error) {
}
return
user
,
nil
}
// getUserDirectly directly checks if an user is allowed to connect
func
getUserDirectly
(
authorizationHeader
string
)
(
TokenData
,
error
)
{
authHeader
:=
strings
.
Split
(
authorizationHeader
,
" "
)
var
user
User
if
authHeader
[
0
]
==
"Basic"
&&
len
(
authHeader
)
==
2
{
decoded
,
err
:=
base64
.
StdEncoding
.
DecodeString
(
authHeader
[
1
])
if
err
==
nil
{
auth
:=
strings
.
Split
(
string
(
decoded
),
":"
)
sentUser
:=
User
{
Login
:
auth
[
0
],
Password
:
auth
[
1
]}
foundUser
,
err
:=
MatchUser
(
sentUser
)
if
err
==
nil
{
return
(
TokenData
{
User
:
foundUser
}),
nil
}
}
}
return
TokenData
{
User
:
user
},
errors
.
New
(
"could not retrieve user directly from basic auth header"
)
}
main.go
View file @
0c8be407
...
...
@@ -41,7 +41,7 @@ func main() {
// mainMux.Handle("/api/common/", http.StripPrefix("/api/common", auth.ValidateAuthMiddleware(commonMux, []string{"*"}, true)))
adminMux
:=
http
.
NewServeMux
()
adminMux
.
HandleFunc
(
"/
api/admin/
newToken"
,
createNewToken
)
adminMux
.
HandleFunc
(
"/newToken"
,
createNewToken
)
mainMux
.
Handle
(
"/api/admin/"
,
http
.
StripPrefix
(
"/api/admin"
,
auth
.
ValidateAuthMiddleware
(
adminMux
,
[]
string
{
os
.
Getenv
(
"ADMIN_ROLE"
)},
true
)))
http
.
ListenAndServe
(
":8080"
,
mainMux
)
...
...
web/assets/fontawesome/fontawesome.min.js
0 → 100644
View file @
0c8be407
This diff is collapsed.
Click to expand it.
web/assets/fontawesome/solid.min.js
0 → 100644
View file @
0c8be407
This diff is collapsed.
Click to expand it.
web/assets/icons/icon.png
0 → 100644
View file @
0c8be407
11.6 KB
web/components/login/login.js
View file @
0c8be407
// Imports
import
*
as
Navbar
from
"
/components/navbar/navbar.js
"
;
// import { loginModes } from "/assets/brand/brand.js";
import
*
as
Auth
from
"
/services/auth/auth.js
"
;
import
{
HandleError
}
from
"
/services/common/errors.js
"
;
import
{
IsEmpty
}
from
"
/services/common/common.js
"
;
// DOM elements
let
mountpoint
;
let
login_field
;
let
password_field
;
let
login_inmemory
;
let
login_icon
;
export
class
Login
{
constructor
(
user
,
navbar
)
{
this
.
user
=
user
;
this
.
navbar
=
navbar
;
}
export
async
function
mount
(
where
)
{
mountpoint
=
where
;
let
user
=
await
Auth
.
GetUser
();
if
(
user
!==
undefined
)
{
document
.
getElementById
(
mountpoint
).
innerHTML
=
""
;
location
.
hash
=
"
#
"
;
}
else
{
Navbar
.
CreateMenu
();
document
.
getElementById
(
mountpoint
).
innerHTML
=
/* HTML */
`
<div class="columns">
<div class="column is-half is-offset-one-quarter">
<div class="card">
<div class="card-content">
<div class="field">
<p class="control has-icons-left has-icons-right">
<input
id="login-login"
class="input"
type="text"
placeholder="Login"
/>
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
</p>
</div>
<div class="field">
<p class="control has-icons-left">
<input
id="login-password"
class="input"
type="password"
placeholder="Password"
/>
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
// DOM elements
login_field
;
password_field
;
login_inmemory
;
login_icon
;
async
mount
(
mountpoint
)
{
if
(
!
IsEmpty
(
this
.
user
))
{
document
.
getElementById
(
mountpoint
).
innerHTML
=
""
;
location
.
hash
=
"
#
"
;
}
else
{
this
.
navbar
.
CreateMenu
();
document
.
getElementById
(
mountpoint
).
innerHTML
=
/* HTML */
`
<div class="columns">
<div class="column is-half is-offset-one-quarter">
<div class="card">
<div class="card-content">
<div class="field">
<p class="control has-icons-left has-icons-right">
<input
id="login-login"
class="input"
type="text"
placeholder="Login"
/>
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
</p>
</div>
<div class="field">
<p class="control has-icons-left">
<input
id="login-password"
class="input"
type="password"
placeholder="Password"
/>
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
</div>
</div>
<footer class="card-footer">
<a id="login-inmemory" class="card-footer-item">
<span class="icon" id="login-icon"
><i class="fas fa-key"></i></span
>Login
</a>
</footer>
</div>
<footer class="card-footer">
<a id="login-inmemory" class="card-footer-item">
<span class="icon" id="login-icon"
><i class="fas fa-key"></i></span
>Login
</a>
</footer>
</div>
</div>
</div>
`
;
registerModalFields
();
}
}
function
registerModalFields
()
{
login_field
=
document
.
getElementById
(
"
login-login
"
);
password_field
=
document
.
getElementById
(
"
login-password
"
);
password_field
.
addEventListener
(
"
keyup
"
,
function
(
event
)
{
// Number 13 is the "Enter" key on the keyboard
if
(
event
.
keyCode
===
13
)
{
doLogin
();
`
;
this
.
registerModalFields
();
}
});
login_inmemory
=
document
.
getElementById
(
"
login-inmemory
"
);
login_inmemory
.
addEventListener
(
"
click
"
,
function
()
{
doLogin
();
});
login_icon
=
document
.
getElementById
(
"
login-icon
"
);
}
}
async
function
doLogin
()
{
login_icon
.
classList
.
add
(
"
fa-pulse
"
);
try
{
const
response
=
await
fetch
(
"
/Login
"
,
{
method
:
"
POST
"
,
body
:
JSON
.
stringify
({
login
:
login_field
.
value
,
password
:
password_field
.
value
,
}),
registerModalFields
()
{
this
.
login_field
=
document
.
getElementById
(
"
login-login
"
);
this
.
password_field
=
document
.
getElementById
(
"
login-password
"
);
this
.
password_field
.
addEventListener
(
"
keyup
"
,
(
event
)
=>
{
// Number 13 is the "Enter" key on the keyboard
if
(
event
.
keyCode
===
13
)
{
this
.
doLogin
();
}
});
this
.
login_inmemory
=
document
.
getElementById
(
"
login-inmemory
"
);
this
.
login_inmemory
.
addEventListener
(
"
click
"
,
function
()
{
this
.
doLogin
();
});
if
(
response
.
status
!==
200
)
{
throw
new
Error
(
`Login error (status
${
response
.
status
}
)`
);
this
.
login_icon
=
document
.
getElementById
(
"
login-icon
"
);
}
async
doLogin
()
{
this
.
login_icon
.
classList
.
add
(
"
fa-pulse
"
);
try
{
const
response
=
await
fetch
(
"
/Login
"
,
{
method
:
"
POST
"
,
body
:
JSON
.
stringify
({
login
:
this
.
login_field
.
value
,
password
:
this
.
password_field
.
value
,
}),
});
if
(
response
.
status
!==
200
)
{
throw
new
Error
(
`Login error (status
${
response
.
status
}
)`
);
}
const
newUser
=
await
Auth
.
GetUser
();
Object
.
assign
(
this
.
user
,
newUser
);
location
.
hash
=
"
#accueil
"
;
this
.
navbar
.
CreateMenu
();
}
catch
(
e
)
{
HandleError
(
e
);
this
.
login_icon
.
classList
.
remove
(
"
fa-pulse
"
);
}
await
Auth
.
GetUser
();
location
.
hash
=
"
#accueil
"
;
Navbar
.
CreateMenu
();
}
catch
(
e
)
{
HandleError
(
e
);
login_icon
.
classList
.
remove
(
"
fa-pulse
"
);
}
}
web/components/navbar/navbar.js
View file @
0c8be407
// Imports
import
*
as
Auth
from
"
/services/auth/auth.js
"
;
//import * as brand from "/assets/brand/brand.js";
import
{
AnimateCSS
}
from
"
/services/common/common.js
"
;
import
{
AnimateCSS
,
IsEmpty
}
from
"
/services/common/common.js
"
;
// local variables
let
user
;
let
menu
;
export
class
Navbar
{
constructor
(
user
)
{
this
.
user
=
user
;
}
// local variables
user
;
menu
;
export
function
mount
(
mountpoint
)
{
const
where
=
document
.
getElementById
(
mountpoint
);
where
.
innerHTML
=
/* HTML */
`
<div class="navbar-brand">
<a
role="button"
id="navbar-burger"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar-menu" class="navbar-menu"></div>
`
;
// Hamburger menu
const
burger
=
document
.
getElementById
(
"
navbar-burger
"
);
menu
=
document
.
getElementById
(
"
navbar-menu
"
);
const
openClose
=
async
(
e
)
=>
{
if
(
burger
.
classList
.
contains
(
"
is-active
"
))
{
await
AnimateCSS
(
menu
,
"
slideOutRight
"
);
menu
.
classList
.
remove
(
"
is-active
"
);
burger
.
classList
.
remove
(
"
is-active
"
);
}
else
{
if
(
e
.
srcElement
==
burger
)
{
menu
.
classList
.
add
(
"
is-active
"
);
burger
.
classList
.
add
(
"
is-active
"
);
AnimateCSS
(
menu
,
"
slideInRight
"
);
mount
(
mountpoint
)
{
const
where
=
document
.
getElementById
(
mountpoint
);
// window.document.title = brand.windowTitle;
where
.
innerHTML
=
/* HTML */
`
<div class="navbar-brand">
<a class="navbar-item is-size-4" href="/">
<img src="assets/icons/icon.png" alt="logo" /> Cyber-Signal
</a>
<a role="button" id="navbar-burger" class="navbar-burger burger" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar-menu" class="navbar-menu"></div>
`
;
// Hamburger menu
const
burger
=
document
.
getElementById
(
"
navbar-burger
"
);
this
.
menu
=
document
.
getElementById
(
"
navbar-menu
"
);
const
openClose
=
async
(
e
)
=>
{
if
(
burger
.
classList
.
contains
(
"
is-active
"
))
{
await
AnimateCSS
(
this
.
menu
,
"
slideOutRight
"
);
this
.
menu
.
classList
.
remove
(
"
is-active
"
);
burger
.
classList
.
remove
(
"
is-active
"
);
}
else
{
if
(
e
.
srcElement
==
burger
||
e
.
srcElement
.
offsetParent
==
burger
)
{
this
.
menu
.
classList
.
add
(
"
is-active
"
);
burger
.
classList
.
add
(
"
is-active
"
);
AnimateCSS
(
this
.
menu
,
"
slideInRight
"
);
}
}
}
};
burger
.
addEventListener
(
"
click
"
,
openClose
);
menu
.
addEventListener
(
"
click
"
,
openClose
);
CreateMenu
();
}
};
burger
.
addEventListener
(
"
click
"
,
openClose
);
this
.
menu
.
addEventListener
(
"
click
"
,
openClose
);
this
.
CreateMenu
();
}
export
async
function
CreateMenu
()
{
user
=
await
Auth
.
GetUser
();
console
.
log
(
user
);
menu
.
innerHTML
=
/* HTML */
`
<div class="navbar-start">
<a id="navbar-accueil" class="navbar-item" href="#accueil">
<i class="navbar-menu-icon fas fa-home"></i>Accueil
</a>
${
user
===
undefined
?
``
:
/* HTML */
`
<a id="navbar-dashboard" class="navbar-item" href="#dashboard">
<i class="navbar-menu-icon fas fa-folder-open"></i>Dashboard
</a>
${
user
.
isAdmin
?
/* HTML */
`
<a
id="navbar-sharetoken"
class="navbar-item"
href="#sharetoken"
>
<i class="navbar-menu-icon fas fa-folder-open"></i>Share
token
</a>
`
:
""
}
`
}
</div>
<div class="navbar-end">
${
user
===
undefined
?
/* HTML */
`
<a class="navbar-item" href="#login">
<i class="navbar-menu-icon fas fa-sign-in-alt"></i>Log in
</a>
`
:
/* HTML */
`
<a class="navbar-item" href="/Logout">
<i class="navbar-menu-icon fas fa-sign-out-alt"></i>Log out
</a>
`
}
</div>
`
;
SetActiveItem
();
}
async
CreateMenu
()
{
this
.
menu
.
innerHTML
=
/* HTML */
`
<div class="navbar-start">
<a id="navbar-accueil" class="navbar-item" href="#accueil">
<i class="navbar-menu-icon fas fa-home"></i>Accueil
</a>
${
IsEmpty
(
this
.
user
)
?
``
:
/* HTML */
`
<a id="navbar-dashboard" class="navbar-item" href="#dashboard">
<i class="navbar-menu-icon fas fa-folder-open"></i>Dashboard
</a>
${
this
.
user
.
isAdmin
?
/* HTML */
`
<a id="navbar-sharetoken" class="navbar-item" href="#sharetoken">
<i class="navbar-menu-icon fas fa-key"></i>Share token
</a>
`
:
""
}
`
}
</div>
<div class="navbar-end">
${
IsEmpty
(
this
.
user
)
?
/* HTML */
`
<a class="navbar-item" href="#login">
<i class="navbar-menu-icon fas fa-sign-in-alt"></i>Log in
</a>
`
:
/* HTML */
`
<a class="navbar-item" href="/Logout">
<i class="navbar-menu-icon fas fa-sign-out-alt"></i>Log out
</a>
`
}
</div>
`
;
this
.
SetActiveItem
();
}
export
function
SetActiveItem
()
{
const
items
=
document
.
getElementsByClassName
(
"
navbar-item
"
);
for
(
const
i
of
items
)
{
i
.
classList
.
remove
(
"
is-active
"
);
if
(
i
.
id
==
"
navbar-
"
+
location
.
hash
.
substring
(
1
))
{
i
.
classList
.
add
(
"
is-active
"
);
SetActiveItem
()
{
const
items
=
document
.
getElementsByClassName
(
"
navbar-item
"
);
for
(
const
i
of
items
)
{
i
.
classList
.
remove
(
"
is-active
"
);
if
(
i
.
id
==
"
navbar-
"
+
location
.
hash
.
substring
(
1
))
{
i
.
classList
.
add
(
"
is-active
"
);
}
}
}
}
web/components/sharetoken/sharetoken.js
View file @
0c8be407
// Imports
import
{
HandleError
}
from
"
/services/common/errors.js
"
;
// DOM elements
let
mountpoint
;
let
new_token_button
;
let
token_textarea
;
let
copy_token_button
;
export
async
function
mount
(
where
,
user
)
{
const
shareTokenComponent
=
new
ShareToken
(
user
);
await
shareTokenComponent
.
mount
(
where
);
}
// Local variables
let
current_user
;
class
ShareToken
{
constructor
(
user
)
{
this
.
current_user
=
user
;
}
export
async
function
mount
(
where
)
{
mountpoint
=
where
;
document
.
getElementById
(
mountpoint
).
innerHTML
=
/* HTML */
` <div
class="container is-fluid"
>
<button id="token-new" class="button is-primary">Générer</button>
<div id="textarea-control" class="control my-2">
<textarea
id="token-textarea"
class="textarea is-info is-medium has-fixed-size"
placeholder="Click the button to generate a token"
disabled="true"
></textarea>
</div>
<button id="token-copy" class="button is-success" disabled="true">
Copier
</button>
</div>`
;
new_token_button
=
document
.
getElementById
(
"
token-new
"
);
new_token_button
.
addEventListener
(
"
click
"
,
function
()
{
generateToken
();
});
token_textarea
=
document
.
getElementById
(
"
token-textarea
"
);
copy_token_button
=
document
.
getElementById
(
"
token-copy
"
);
copy_token_button
.
addEventListener
(
"
click
"
,
function
()
{
copy
(
token_textarea
);
});
}
// DOM elements
new_token_button
;
token_textarea
;
copy_token_button
;
async
function
generateToken
()
{
const
control
=
document
.
getElementById
(
"
textarea-control
"
);
control
.
classList
.
add
(
"
is-loading
"
);
try
{
const
response
=
await
fetch
(
"
/api/admin/newToken
"
,
{
method
:
"
POST
"
,
headers
:
new
Headers
({
"
XSRF-Token
"
:
this
.
user
.
xsrftoken
,
})
async
mount
(
mountpoint
)
{
document
.
getElementById
(
mountpoint
).
innerHTML
=
/* HTML */
` <div
class="container is-fluid"
>
<button id="token-new" class="button is-primary">Générer</button>
<div id="textarea-control" class="control my-2">
<textarea
id="token-textarea"
class="textarea is-info is-medium has-fixed-size"
placeholder="Click the button to generate a token"
disabled="true"
></textarea>
</div>
<button id="token-copy" class="button is-success" disabled="true">
Copier
</button>
</div>`
;
this
.
new_token_button
=
document
.
getElementById
(
"
token-new
"
);
this
.
new_token_button
.
addEventListener
(
"
click
"
,
async
()
=>
{
await
this
.
generateToken
();
});
this
.
token_textarea
=
document
.
getElementById
(
"
token-textarea
"
);
this
.
copy_token_button
=
document
.
getElementById
(
"
token-copy
"
);
this
.
copy_token_button
.
addEventListener
(
"
click
"
,
function
()
{
this
.
copy
(
token_textarea
);
});
if
(
response
.
status
!==
200
)
{
throw
new
Error
(
`Le token n'a pas pu être généré (code
${
response
.
status
}
)`
);
}
async
generateToken
()
{
const
control
=
document
.
getElementById
(
"
textarea-control
"
);
control
.
classList
.
add
(
"
is-loading
"
);
try
{
const
response
=
await
fetch
(
"
/api/admin/newToken
"
,
{
method
:
"
POST
"
,
headers
:
new
Headers
({
"
XSRF-Token
"
:
this
.
current_user
.
xsrftoken
,
}),
});
if
(
response
.
status
!==
200
)
{
throw
new
Error
(
`Le token n'a pas pu être généré (code
${
response
.
status
}
)`
);
}
const
responseText
=
await
response
.
text
();
this
.
token_textarea
.
disabled
=
false
;
this
.
token_textarea
.
value
=
responseText
;
this
.
copy_token_button
.
disabled
=
false
;
}
catch
(
e
)
{
HandleError
(
e
);
this
.
token_textarea
.
value
=
"
Une erreur s'est produite !
"
;
}
const
responseText
=
await
response
.
text
();
token_textarea
.
disabled
=
false
;
token_textarea
.
value
=
responseText
;
copy_token_button
.
disabled
=
false
;
}
catch
(
e
)
{
HandleError
(
e
);
token_textarea
.
value
=
"
Une erreur s'est produite !
"
;
control
.
classList
.
remove
(
"
is-loading
"
);
}
control
.
classList
.
remove
(
"
is-loading
"
);
}
function
copy
(
textarea
)
{
textarea
.
select
();
document
.
execCommand
(
"
copy
"
);
copy_token_button
.
textContent
=
"
Copié !
"
;
copy
(
textarea
)
{
textarea
.
select
();
document
.
execCommand
(
"
copy
"
);
this
.
copy_token_button
.
textContent
=
"
Copié !
"
;
}
}
web/index.html
View file @
0c8be407
...
...
@@ -7,8 +7,11 @@
<link
rel=
"stylesheet"
href=
"assets/bulma.min.css"
/>
<link
rel=
"stylesheet"
href=
"assets/animate.min.css"
/>
<link
rel=
"icon"
href=
"assets/icons/icon.png"
>