token-validator: use SuffixIP, can modify it and can delete tunnels
This commit is contained in:
parent
060831d9c2
commit
da1920673d
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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">❌</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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
Reference in New Issue