token-validator: use SuffixIP, can modify it and can delete tunnels

This commit is contained in:
nemunaire 2021-03-02 19:08:42 +01:00
parent 060831d9c2
commit da1920673d
4 changed files with 137 additions and 9 deletions

View File

@ -94,7 +94,7 @@ type TunnelToken struct {
Dump *WGDump
}
func tokenFromText(token string) []byte {
func TokenFromText(token string) []byte {
sha := sha512.Sum512([]byte(token))
return sha[:]
}
@ -118,7 +118,7 @@ func (student Student) NewTunnelToken(suffixip int) (t TunnelToken, err error) {
}
t.TokenText = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(base64.RawStdEncoding.EncodeToString(tok), "/", ".", -1), "+", "_", -1), "O", "#", -1), "l", "$", -1), "I", ">", -1)
t.token = tokenFromText(t.TokenText)
t.token = TokenFromText(t.TokenText)
t.IdStudent = student.Id
_, err = DBExec("INSERT INTO student_tunnel_tokens (token, token_text, id_student, time, suffixip, version) VALUES (?, ?, ?, ?, ?, 0)", t.token, t.TokenText, student.Id, time.Now(), suffixip)
@ -194,7 +194,7 @@ func (student Student) GetTunnelToken(token []byte) (t TunnelToken, err error) {
}
func (t *TunnelToken) Update() (int64, error) {
newtoken := tokenFromText(t.TokenText)
newtoken := TokenFromText(t.TokenText)
tm := time.Now()
if res, err := DBExec("UPDATE student_tunnel_tokens SET token = ?, token_text = ?, id_student = ?, pubkey = ?, time = ?, suffixip = ?, version = ? WHERE token = ?", newtoken, t.TokenText, t.IdStudent, t.PubKey, tm, t.SuffixIP, t.Version, t.token); err != nil {
@ -208,6 +208,16 @@ func (t *TunnelToken) Update() (int64, error) {
}
}
func (t *TunnelToken) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM student_tunnel_tokens WHERE token = ? AND id_student = ?", t.token, t.IdStudent); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func GetStudentsTunnels() (ts []TunnelToken, err error) {
if rows, errr := DBQuery("SELECT T.token, T.token_text, T.id_student, T.pubkey, T.time, T.suffixip, T.version FROM student_tunnel_tokens T INNER JOIN (SELECT B.id_student, MAX(B.time) AS time FROM student_tunnel_tokens B WHERE B.pubkey IS NOT NULL GROUP BY id_student) L ON T.id_student = L.id_student AND T.time = L.time"); errr != nil {
return nil, errr

View File

@ -44,6 +44,17 @@ angular.module("AdLinApp")
}
})
.directive('integer', function() {
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(function(viewValue){
return parseInt(viewValue, 10);
});
}
};
})
.component('toast', {
bindings: {
date: '=',
@ -150,7 +161,10 @@ angular.module("AdLinApp")
};
$scope.updateTunnelInfo();
$scope.updateTunnelsList = function() {
var noUpdate = 0
$scope.updateTunnelsList = function() {
if (noUpdate == 0)
$http({
method: 'GET',
url: "api/wg/",
@ -211,11 +225,48 @@ angular.module("AdLinApp")
});
}
$scope.editTunnel = function(tunnel) {
tunnel.edit = true;
noUpdate++;
tunnel.newData = {
TokenText: tunnel.TokenText,
SuffixIP: tunnel.SuffixIP,
}
};
$scope.updateTunnel = function(tunnel) {
tunnel.pleaseWaitUpdate = true;
$http({
method: 'PUT',
url: "api/wg/" + encodeURIComponent(tunnel.TokenText),
data: tunnel.newData
}).then(function(response) {
noUpdate--;
tunnel.SuffixIP = tunnel.newData.SuffixIP;
tunnel.TokenText = tunnel.newData.TokenText;
tunnel.edit = false;
tunnel.pleaseWaitUpdate = false;
$scope.updateTunnelsList();
$scope.addToast({
variant: "success",
title: "Maatma Tunnels",
msg: "Tunnel mise à jour avec succès !",
});
}, function(response) {
tunnel.pleaseWaitUpdate = false;
$scope.addToast({
variant: "danger",
title: "Maatma Tunnels",
msg: (response.data ? response.data.errmsg : "Impossible de contacter le serveur"),
});
});
}
$scope.dropTunnel = function(tunnel) {
tunnel.pleaseWaitDrop = true;
$http({
method: 'DELETE',
url: "api/wg/" + tunnel.TokenText,
url: "api/wg/" + encodeURIComponent(tunnel.TokenText),
data: {}
}).then(function(response) {
$scope.updateTunnelsList();

View File

@ -7,6 +7,7 @@
<tr>
<th></th>
<th>Token</th>
<th>Suffix</th>
<th>Dernière utilisation</th>
<th>Clef publique</th>
</tr>
@ -18,10 +19,22 @@
<span ng-if="!tunnel.Dump">&#x274c;</span>
</td>
<td><code>{{ tunnel.TokenText }}</code></td>
<td ng-if="tunnel.edit">
<input class="form-control" ng-model="tunnel.newData.SuffixIP" placeholder="Suffixe d'IP par défaut" autofocus integer>
</td>
<td ng-if="!tunnel.edit && tunnel.SuffixIP">{{ tunnel.SuffixIP }}</td>
<td ng-if="!tunnel.edit && !tunnel.SuffixIP">Par défaut</td>
<td>{{ tunnel.Time | date:"medium" }}<span ng-if="tunnel.Version"> (VM TP {{ tunnel.Version }})</span></td>
<td><code ng-show="tunnel.PubKey">{{ tunnel.PubKey }}</code><span ng-show="!tunnel.PubKey">(none)</span></td>
<td><code class="text-truncate" title="{{ tunnel.PubKey }}" ng-show="tunnel.PubKey">{{ tunnel.PubKey }}</code><span ng-show="!tunnel.PubKey">(none)</span></td>
<td>
<button class="btn btn-sm btn-danger" ng-click="dropTunnel(tunnel)" disabled>
<button class="btn btn-sm btn-info" ng-click="editTunnel(tunnel)" ng-if="!tunnel.edit">
Éditer
</button>
<button class="btn btn-sm btn-success" ng-click="updateTunnel(tunnel)" ng-if="tunnel.edit">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" ng-show="tunnel.pleaseWaitUpdate"></span>
Enregistrer
</button>
<button class="btn btn-sm btn-danger" ng-click="dropTunnel(tunnel)">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" ng-show="tunnel.pleaseWaitDrop"></span>
Révoquer
</button>

View File

@ -33,6 +33,8 @@ func init() {
router.POST("/api/wg/", apiAuthHandler(genWgToken))
router.GET("/api/wg/:token", getWgTunnelInfo)
router.POST("/api/wg/:token", getWgTunnelInfo)
router.PUT("/api/wg/:token", apiAuthHandler(updateWgTunnel))
router.DELETE("/api/wg/:token", apiAuthHandler(deleteWgTunnel))
}
func showWgTunnel(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
@ -121,6 +123,11 @@ func getWgTunnelInfo(w http.ResponseWriter, r *http.Request, ps httprouter.Param
return
}
// 0 is considered default for suffix, apply default now
if token.SuffixIP <= 0 {
token.SuffixIP = 1
}
syncWgConf()
tinfo := getTunnelInfo(token.IdStudent)
@ -138,11 +145,58 @@ PublicKey = %s
Endpoint = %s:%d
AllowedIPs = ::/0
PersistentKeepalive = 5
# MyIPv6=%s1/%d
# MyIPv6=%s%x/%d
# MyNetwork=%s/%d
# GWIPv6=%s
# MyLogin=%s
`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login)))
`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, token.SuffixIP, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login)))
}
func updateWgTunnel(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
token, err := adlin.GetTunnelToken(adlin.TokenFromText(ps.ByName("token")))
if err != nil {
return nil, err
}
if token.IdStudent != student.Id {
return nil, fmt.Errorf("Unauthorized")
}
var newToken adlin.TunnelToken
if err := json.Unmarshal(body, &newToken); err != nil {
return nil, err
}
token.TokenText = newToken.TokenText
token.PubKey = newToken.PubKey
token.SuffixIP = newToken.SuffixIP
if _, err = token.Update(); err != nil {
return nil, err
}
syncWgConf()
return true, err
}
func deleteWgTunnel(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
token, err := adlin.GetTunnelToken(adlin.TokenFromText(ps.ByName("token")))
if err != nil {
return nil, err
}
if token.IdStudent != student.Id {
return nil, fmt.Errorf("Unauthorized")
}
if _, err = token.Delete(); err != nil {
return nil, err
}
syncWgConf()
return true, err
}
func GenWGConfig(w io.Writer) error {