mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-10 18:24:44 +00:00
Implement API keys
This commit is contained in:
parent
80c2b32b92
commit
20a018db2e
File diff suppressed because one or more lines are too long
@ -321,6 +321,10 @@ func getQR(w http.ResponseWriter, params martini.Params) {
|
|||||||
|
|
||||||
func basic(username string, passhash string) http.HandlerFunc {
|
func basic(username string, passhash string) http.HandlerFunc {
|
||||||
return func(res http.ResponseWriter, req *http.Request) {
|
return func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
if validAPIKey(req.Header.Get("X-API-Key")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
error := func() {
|
error := func() {
|
||||||
time.Sleep(time.Duration(rand.Intn(100)+100) * time.Millisecond)
|
time.Sleep(time.Duration(rand.Intn(100)+100) * time.Millisecond)
|
||||||
res.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
|
res.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
|
||||||
@ -358,6 +362,10 @@ func basic(username string, passhash string) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validAPIKey(k string) bool {
|
||||||
|
return len(cfg.GUI.APIKey) > 0 && k == cfg.GUI.APIKey
|
||||||
|
}
|
||||||
|
|
||||||
func embeddedStatic() func(http.ResponseWriter, *http.Request, *log.Logger) {
|
func embeddedStatic() func(http.ResponseWriter, *http.Request, *log.Logger) {
|
||||||
var modt = time.Now().UTC().Format(http.TimeFormat)
|
var modt = time.Now().UTC().Format(http.TimeFormat)
|
||||||
|
|
||||||
|
@ -22,6 +22,9 @@ var csrfMut sync.Mutex
|
|||||||
// the request with 403. For / and /index.html, set a new CSRF cookie if none
|
// the request with 403. For / and /index.html, set a new CSRF cookie if none
|
||||||
// is currently set.
|
// is currently set.
|
||||||
func csrfMiddleware(w http.ResponseWriter, r *http.Request) {
|
func csrfMiddleware(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if validAPIKey(r.Header.Get("X-API-Key")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, "/rest/") {
|
if strings.HasPrefix(r.URL.Path, "/rest/") {
|
||||||
token := r.Header.Get("X-CSRF-Token")
|
token := r.Header.Get("X-CSRF-Token")
|
||||||
if !validCsrfToken(token) {
|
if !validCsrfToken(token) {
|
||||||
|
@ -123,6 +123,7 @@ type GUIConfiguration struct {
|
|||||||
User string `xml:"user,omitempty"`
|
User string `xml:"user,omitempty"`
|
||||||
Password string `xml:"password,omitempty"`
|
Password string `xml:"password,omitempty"`
|
||||||
UseTLS bool `xml:"tls,attr"`
|
UseTLS bool `xml:"tls,attr"`
|
||||||
|
APIKey string `xml:"apikey,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDefaults(data interface{}) error {
|
func setDefaults(data interface{}) error {
|
||||||
|
17
gui/app.js
17
gui/app.js
@ -52,6 +52,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
|||||||
{id: 'User', descr: 'GUI Authentication User', type: 'text', restart: true},
|
{id: 'User', descr: 'GUI Authentication User', type: 'text', restart: true},
|
||||||
{id: 'Password', descr: 'GUI Authentication Password', type: 'password', restart: true},
|
{id: 'Password', descr: 'GUI Authentication Password', type: 'password', restart: true},
|
||||||
{id: 'UseTLS', descr: 'Use HTTPS for GUI', type: 'bool', restart: true},
|
{id: 'UseTLS', descr: 'Use HTTPS for GUI', type: 'bool', restart: true},
|
||||||
|
{id: 'APIKey', descr: 'API Key', type: 'apikey'},
|
||||||
];
|
];
|
||||||
|
|
||||||
function getSucceeded() {
|
function getSucceeded() {
|
||||||
@ -514,6 +515,10 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
|||||||
$http.post(urlbase + '/config', JSON.stringify($scope.config), {headers: {'Content-Type': 'application/json'}});
|
$http.post(urlbase + '/config', JSON.stringify($scope.config), {headers: {'Content-Type': 'application/json'}});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.setAPIKey = function (cfg) {
|
||||||
|
cfg.APIKey = randomString(30, 32);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$http.get(urlbase + '/version').success(function (data) {
|
$http.get(urlbase + '/version').success(function (data) {
|
||||||
$scope.version = data;
|
$scope.version = data;
|
||||||
@ -593,6 +598,18 @@ function decimals(val, num) {
|
|||||||
return decs;
|
return decs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function randomString(len, bits)
|
||||||
|
{
|
||||||
|
bits = bits || 36;
|
||||||
|
var outStr = "", newStr;
|
||||||
|
while (outStr.length < len)
|
||||||
|
{
|
||||||
|
newStr = Math.random().toString(bits).slice(2);
|
||||||
|
outStr += newStr.slice(0, Math.min(newStr.length, (len - outStr.length)));
|
||||||
|
}
|
||||||
|
return outStr.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
syncthing.filter('natural', function () {
|
syncthing.filter('natural', function () {
|
||||||
return function (input, valid) {
|
return function (input, valid) {
|
||||||
return input.toFixed(decimals(input, valid));
|
return input.toFixed(decimals(input, valid));
|
||||||
|
@ -595,6 +595,11 @@ found in the LICENSE file.
|
|||||||
{{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="config.workingGUI[setting.id]"></input>
|
{{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="config.workingGUI[setting.id]"></input>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div ng-if="setting.type == 'apikey'">
|
||||||
|
<label>{{setting.descr}} (<a href="http://discourse.syncthing.net/t/v0-8-14-api-keys/335">Usage</a>)</label>
|
||||||
|
<div class="well well-sm text-monospace">{{config.workingGUI[setting.id] || "-"}}</div>
|
||||||
|
<button type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(config.workingGUI)">Generate</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user