Browse Source

Playing around with keygen element.

pull/28/head
Simon Eisenmann 12 years ago
parent
commit
69039af618
  1. 174
      src/app/spreed-speakfreely-server/users.go
  2. 4
      static/js/directives/settings.js
  3. 67
      static/js/services/mediastream.js
  4. 28
      static/partials/settings.html

174
src/app/spreed-speakfreely-server/users.go

@ -23,14 +23,22 @@ package main @@ -23,14 +23,22 @@ package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"github.com/longsleep/pkac"
"github.com/satori/go.uuid"
"github.com/strukturag/phoenix"
"io/ioutil"
"log"
"math/big"
"net/http"
"strconv"
"strings"
@ -111,6 +119,115 @@ func (uh *UsersHTTPHeaderHandler) Create(un *UserNonce, request *http.Request) ( @@ -111,6 +119,115 @@ func (uh *UsersHTTPHeaderHandler) Create(un *UserNonce, request *http.Request) (
}
func loadPEMfromFile(fn string) (block *pem.Block, err error) {
data, err := ioutil.ReadFile(fn)
if err != nil {
return
}
block, _ = pem.Decode(data)
return block, nil
}
type UsersCertificateHandler struct {
validFor time.Duration
privateKey *rsa.PrivateKey
certificate *x509.Certificate
}
func (uh *UsersCertificateHandler) loadPrivateKey(fn string) error {
pemBlock, err := loadPEMfromFile(fn)
if err != nil {
return err
}
privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
if err != nil {
return err
}
uh.privateKey = privateKey
log.Printf("Users certificate private key loaded from %s\n", fn)
return nil
}
func (uh *UsersCertificateHandler) loadCertificate(fn string) error {
pemBlock, err := loadPEMfromFile(fn)
if err != nil {
return err
}
certificates, err := x509.ParseCertificates(pemBlock.Bytes)
if err != nil {
return err
}
uh.certificate = certificates[0]
log.Printf("Users certificate loaded from %s\n", fn)
return nil
}
func (uh *UsersCertificateHandler) makeTemplate(serialNumber string) *x509.Certificate {
notBefore := time.Now()
notAfter := notBefore.Add(uh.validFor)
return &x509.Certificate{
SerialNumber: big.NewInt(42),
Subject: pkix.Name{
SerialNumber: serialNumber,
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: false,
}
}
func (uh *UsersCertificateHandler) Validate(snr *SessionNonceRequest, request *http.Request) (string, error) {
return "", errors.New("certificate validation not implemented")
}
func (uh *UsersCertificateHandler) Create(un *UserNonce, request *http.Request) (*UserNonce, error) {
spkac := request.Form.Get("pubkey")
if spkac == "" {
return nil, errors.New("no spkac provided")
}
spkacDerBytes, err := base64.StdEncoding.DecodeString(spkac)
if err != nil {
return nil, errors.New(fmt.Sprintf("spkac invalid: %s", err))
}
publicKey, err := pkac.ParseSPKAC(spkacDerBytes)
if err != nil {
return nil, errors.New(fmt.Sprintf("unable to parse spkac: %s", err))
}
template := uh.makeTemplate(un.Userid)
certDerBytes, err := x509.CreateCertificate(rand.Reader, template, uh.certificate, publicKey, uh.privateKey)
if err != nil {
return nil, errors.New(fmt.Sprintf("failed to create certificate: %s", err))
}
log.Println("Generated new certificate", un.Userid)
un.SetResponse(certDerBytes, "application/x-x509-user-cert", http.Header{
"Content-Length": {strconv.Itoa(len(certDerBytes))},
"Accept-Ranges": {"bytes"},
"Last-Modified": {time.Now().UTC().Format(http.TimeFormat)},
})
return un, nil
}
type UserNonce struct {
Nonce string `json:"nonce"`
Userid string `json:"userid"`
@ -118,6 +235,28 @@ type UserNonce struct { @@ -118,6 +235,28 @@ type UserNonce struct {
Secret string `json:"secret"`
Timestamp int64 `json:"timestamp"`
Success bool `json:"success"`
raw []byte
contentType string
header http.Header
}
func (un *UserNonce) SetResponse(raw []byte, contentType string, header http.Header) {
un.raw = raw
un.contentType = contentType
un.header = header
}
func (un *UserNonce) Response() (int, interface{}, http.Header) {
header := un.header
if header == nil {
header = http.Header{}
}
if un.contentType != "" {
header.Set("Content-Type", un.contentType)
return 200, un.raw, header
} else {
return 200, un, header
}
}
type Users struct {
@ -143,6 +282,18 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users { @@ -143,6 +282,18 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users {
headerName = "x-users"
}
handler = &UsersHTTPHeaderHandler{headerName: headerName}
case "certificate":
uh := &UsersCertificateHandler{}
uh.validFor = 24 * time.Hour * 365
keyFn, _ := runtime.GetString("users", "certificate_key")
certificateFn, _ := runtime.GetString("users", "certificate_certificate")
if keyFn != "" && certificateFn != "" {
uh.loadPrivateKey(keyFn)
}
if certificateFn != "" {
uh.loadCertificate(certificateFn)
}
handler = uh
default:
mode = ""
}
@ -164,11 +315,22 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users { @@ -164,11 +315,22 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users {
// Post is used to create new userids for this server.
func (users *Users) Post(request *http.Request) (int, interface{}, http.Header) {
decoder := json.NewDecoder(request.Body)
var snr SessionNonceRequest
err := decoder.Decode(&snr)
if err != nil {
return 400, NewApiError("users_bad_request", "Failed to parse request"), http.Header{"Content-Type": {"application/json"}}
var snr *SessionNonceRequest
switch request.Header.Get("Content-Type") {
case "application/json":
decoder := json.NewDecoder(request.Body)
err := decoder.Decode(snr)
if err != nil {
return 400, NewApiError("users_bad_request", "Failed to parse request"), http.Header{"Content-Type": {"application/json"}}
}
case "application/x-www-form-urlencoded":
snr = &SessionNonceRequest{
Id: request.Form.Get("id"),
Sid: request.Form.Get("sid"),
}
default:
return 400, NewApiError("users_invalid_request", "Invalid request type"), http.Header{"Content-Type": {"application/json"}}
}
// Make sure that we have a Sid.
@ -195,6 +357,6 @@ func (users *Users) Post(request *http.Request) (int, interface{}, http.Header) @@ -195,6 +357,6 @@ func (users *Users) Post(request *http.Request) (int, interface{}, http.Header)
}
log.Printf("Users create successfull %s -> %s\n", snr.Id, un.Userid)
return 200, un, http.Header{"Content-Type": {"application/json"}}
return un.Response()
}

4
static/js/directives/settings.js

@ -127,10 +127,10 @@ define(['underscore', 'text!partials/settings.html'], function(_, template) { @@ -127,10 +127,10 @@ define(['underscore', 'text!partials/settings.html'], function(_, template) {
}
};
$scope.registerUserid = function() {
$scope.registerUserid = function(btn) {
console.log("No userid - creating one ...");
mediaStream.users.register(function(data) {
mediaStream.users.register(btn.form, function(data) {
console.info("Created new userid:", data.userid);
if (data.nonce) {
// If the server provided us a nonce, we can do everthing on our own.

67
static/js/services/mediastream.js

@ -65,32 +65,51 @@ define([ @@ -65,32 +65,51 @@ define([
}
},
users: {
register: function(success_cb, error_cb) {
register: function(form, success_cb, error_cb) {
var url = mediaStream.url.api("users");
var data = {
id: mediaStream.api.id,
sid: mediaStream.api.sid
}
$http({
method: "POST",
url: url,
data: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
}).
success(function(data, status) {
if (data.userid !== "" && data.success) {
success_cb(data, status);
} else {
if (error_cb) {
error_cb(data, status);
}
if (form) {
$(form).attr("action", url).attr("method", "POST");
var idE = $('<input name="id" type="hidden">');
idE.val(mediaStream.api.id);
var sidE = $('<input name="sid" type="hidden">');
sidE.val(mediaStream.api.sid);
$(form).append(idE);
$(form).append(sidE);
var iframe = $(form).find("iframe");
console.log("xxxx", iframe[0]);
form.submit();
$timeout(function() {
idE.remove();
sidE.remove();
idE=null;
sidE=null;
}, 0);
} else {
var data = {
id: mediaStream.api.id,
sid: mediaStream.api.sid
}
}).
error(function(data, status) {
if (error_cb) {
error_cb(data, status)
}
});
$http({
method: "POST",
url: url,
data: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
}).
success(function(data, status) {
if (data.userid !== "" && data.success) {
success_cb(data, status);
} else {
if (error_cb) {
error_cb(data, status);
}
}
}).
error(function(data, status) {
if (error_cb) {
error_cb(data, status)
}
});
}
},
authorize: function(data, success_cb, error_cb) {
var url = mediaStream.url.api("sessions") + "/" + mediaStream.api.id + "/";

28
static/partials/settings.html

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<div class="settings nicescroll">
<div class="version">{{version}}</div>
<form class="form-horizontal" on-enter="saveSettings(user)" on-escape="reset()"
<div class="form-horizontal" on-enter="saveSettings(user)" on-escape="reset()"
<fieldset>
<legend>{{_('Settings')}}</legend>
@ -27,17 +27,31 @@ @@ -27,17 +27,31 @@
</div>
</div>
<div class="form-group" ng-if="withUsers || userid">
<label class="col-xs-4 control-label">{{_('Your ID')}} {{serverCfg|json}}</label>
<div class="col-xs-8">
<label class="col-xs-4 control-label">{{_('Your ID')}}</label>
<form class="col-xs-8" target="users_registration_certificate_iframe">
<keygen style="display:none" name="pubkey"/>
<label ng-if="!userid && withUsersRegistration">
<a class="btn btn-small btn-primary" ng-click="registerUserid()">{{_('Register')}}</a>
<button class="btn btn-small btn-primary" ng-click="registerUserid($event.target)">{{_('Register')}}</button>
</label>
<pre class="small" ng-if="userid">{{userid}}</pre>
<iframe style="display:none" name="users_registration_certificate_iframe"></iframe>
</form>
<div ng-if="false" class="col-xs-8">
<label ng-if="!userid && withUsersRegistration">
<button class="btn btn-small btn-primary" ng-click="registerUserid($event.target)">{{_('Register')}}</button>
</label>
<span class="help-block" ng-if="!userid && withUsersRegistration">{{_('Only register an ID if this is your private browser.')}}</span>
<pre class="small" ng-if="userid">{{userid}}</pre>
<label ng-if="userid && loadedUserlogin">
<a class="btn btn-small btn-default" ng-click="forgetUserid()">{{_('Log out')}}</a>
<button class="btn btn-small btn-default" ng-click="forgetUserid()">{{_('Log out')}}</button>
</label>
</div>
<div class="col-xs-8 col-xs-offset-4" ng-if="!userid && withUsersRegistration">
<span class="help-block">{{_('Only register an ID if this is your private browser.')}}</span>
</div>
</div>
<hr/>
<div ng-show="mediaSources.supported" class="form-group">
@ -152,5 +166,5 @@ @@ -152,5 +166,5 @@
</div>
</fieldset>
</form>
</div>
</div>

Loading…
Cancel
Save