Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IRMA
Github mirrors
irmago
Commits
6e9d0360
Commit
6e9d0360
authored
Jan 17, 2020
by
David Venhoek
Committed by
Sietse Ringers
Dec 11, 2020
Browse files
Added initial (very rough) version of keyshare core server.
parent
a800ad0e
Changes
34
Hide whitespace changes
Inline
Side-by-side
irmaconfig.go
View file @
6e9d0360
...
...
@@ -48,6 +48,9 @@ type Configuration struct {
// (i.e., invalid signature, parsing error), and the problem that occurred when parsing them
DisabledSchemeManagers
map
[
SchemeManagerIdentifier
]
*
SchemeManagerError
// Listeners for configuration changes from initialization and updating of the schemes
UpdateListeners
[]
ConfigurationListener
// Path to the irma_configuration folder that this instance represents
Path
string
PrivateKeys
PrivateKeyRing
...
...
@@ -64,6 +67,9 @@ type Configuration struct {
readOnly
bool
}
// ConfigurationListeners are the interface provided to react to changes in schemes.
type
ConfigurationListener
func
(
conf
*
Configuration
)
type
UnknownIdentifierError
struct
{
ErrorType
Missing
*
IrmaIdentifierSet
...
...
@@ -179,6 +185,7 @@ func (conf *Configuration) ParseFolder() (err error) {
}
conf
.
initialized
=
true
conf
.
CallListeners
()
if
mgrerr
!=
nil
{
return
mgrerr
}
...
...
@@ -780,6 +787,8 @@ func (conf *Configuration) join(other *Configuration) {
for
key
,
val
:=
range
other
.
publicKeys
{
conf
.
publicKeys
[
key
]
=
val
}
conf
.
CallListeners
()
}
func
(
e
*
UnknownIdentifierError
)
Error
()
string
{
...
...
@@ -852,3 +861,9 @@ func firstExistingPath(paths []string) string {
}
return
""
}
func
(
conf
*
Configuration
)
CallListeners
()
{
for
_
,
listener
:=
range
conf
.
UpdateListeners
{
listener
(
conf
)
}
}
keyshareServerCore/conf.go
0 → 100644
View file @
6e9d0360
package
keyshareServerCore
import
(
"encoding/binary"
"io/ioutil"
"os"
"strings"
"github.com/privacybydesign/irmago/internal/common"
"github.com/privacybydesign/irmago/keyshareCore"
"github.com/dgrijalva/jwt-go"
"github.com/go-errors/errors"
irma
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server"
"github.com/sirupsen/logrus"
)
// Configuration contains configuration for the irmaserver library and irmad.
type
Configuration
struct
{
// Irma server configuration. If not given, this will be populated using information here
ServerConfiguration
*
server
.
Configuration
`json:"-"`
// Path to IRMA schemes to parse into server configuration (only used if ServerConfiguration == nil).
// If left empty, default value is taken using DefaultSchemesPath().
// If an empty folder is specified, default schemes (irma-demo and pbdf) are downloaded into it.
SchemesPath
string
`json:"schemes_path" mapstructure:"schemes_path"`
// If specified, schemes found here are copied into SchemesPath (only used if ServerConfiguration == nil)
SchemesAssetsPath
string
`json:"schemes_assets_path" mapstructure:"schemes_assets_path"`
// Disable scheme updating (used only if ServerConfiguration == nil)
DisableSchemesUpdate
bool
`json:"disable_schemes_update" mapstructure:"disable_schemes_update"`
// Update all schemes every x minutes (default value 0 means 60) (use DisableSchemesUpdate to disable)
// (used only if ServerConfiguration == nil)
SchemesUpdateInterval
int
`json:"schemes_update" mapstructure:"schemes_update"`
// Path to issuer private keys to parse
IssuerPrivateKeysPath
string
`json:"privkeys" mapstructure:"privkeys"`
// URL at which the IRMA app can reach this keyshare server during sessions
URL
string
`json:"url" mapstructure:"url"`
// Required to be set to true if URL does not begin with https:// in production mode.
// In this case, the server would communicate with IRMA apps over plain HTTP. You must otherwise
// ensure (using eg a reverse proxy with TLS enabled) that the attributes are protected in transit.
DisableTLS
bool
`json:"no_tls" mapstructure:"no_tls"`
// Configuration of secure Core
// Private key used to sign JWTs with
JwtKeyId
int
`json:"jwt_key_id" mapstructure:"jwt_key_id"`
JwtPrivateKey
string
`json:"jwt_privkey" mapstructure:"jwt_privkey"`
JwtPrivateKeyFile
string
`json:"jwt_privkey_file" mapstructure:"jwt_privkey_file"`
// Decryption keys used for keyshare packets
StorageFallbackKeyFiles
[]
string
`json:"storage_fallback_key_files" mapstructure:"storage_fallback_key_files"`
StoragePrimaryKeyFile
string
`json:"storage_primary_key_file" mapstructure:"storage_primary_key_file"`
// Keyshare credential to issue during registration
KeyshareCredential
string
KeyshareAttribute
string
// Logging verbosity level: 0 is normal, 1 includes DEBUG level, 2 includes TRACE level
Verbose
int
`json:"verbose" mapstructure:"verbose"`
// Don't log anything at all
Quiet
bool
`json:"quiet" mapstructure:"quiet"`
// Output structured log in JSON format
LogJSON
bool
`json:"log_json" mapstructure:"log_json"`
// Custom logger instance. If specified, Verbose, Quiet and LogJSON are ignored.
Logger
*
logrus
.
Logger
`json:"-"`
// Production mode: enables safer and stricter defaults and config checking
Production
bool
`json:"production" mapstructure:"production"`
}
func
readAESKey
(
filename
string
)
(
uint32
,
keyshareCore
.
AesKey
,
error
)
{
keyFile
,
err
:=
os
.
Open
(
filename
)
if
err
!=
nil
{
return
0
,
keyshareCore
.
AesKey
{},
err
}
defer
keyFile
.
Close
()
keyData
,
err
:=
ioutil
.
ReadAll
(
keyFile
)
if
err
!=
nil
{
return
0
,
keyshareCore
.
AesKey
{},
err
}
if
len
(
keyData
)
!=
32
+
4
{
return
0
,
keyshareCore
.
AesKey
{},
errors
.
New
(
"Invalid aes key"
)
}
var
key
[
32
]
byte
copy
(
key
[
:
],
keyData
[
4
:
36
])
return
binary
.
LittleEndian
.
Uint32
(
keyData
[
0
:
4
]),
key
,
nil
}
// Process a passed configuration to ensure all field values are valid and initialized
// as required by the rest of this keyshare server component.
func
processConfiguration
(
conf
*
Configuration
)
(
*
keyshareCore
.
KeyshareCore
,
error
)
{
// Setup log
if
conf
.
Logger
==
nil
{
conf
.
Logger
=
server
.
NewLogger
(
conf
.
Verbose
,
conf
.
Quiet
,
conf
.
LogJSON
)
}
server
.
Logger
=
conf
.
Logger
irma
.
Logger
=
conf
.
Logger
// Setup server configuration if needed
if
conf
.
ServerConfiguration
==
nil
{
conf
.
ServerConfiguration
=
&
server
.
Configuration
{
SchemesPath
:
conf
.
SchemesPath
,
SchemesAssetsPath
:
conf
.
SchemesAssetsPath
,
DisableSchemesUpdate
:
conf
.
DisableSchemesUpdate
,
SchemesUpdateInterval
:
conf
.
SchemesUpdateInterval
,
IssuerPrivateKeysPath
:
conf
.
IssuerPrivateKeysPath
,
DisableTLS
:
conf
.
DisableTLS
,
Logger
:
conf
.
Logger
,
}
}
// Force loggers to match (TODO: reevaluate once logging is reworked in irma server)
conf
.
ServerConfiguration
.
Logger
=
conf
.
Logger
// Force production status to match
conf
.
ServerConfiguration
.
Production
=
conf
.
Production
// Load configuration (because server setup needs this to be in place)
if
conf
.
ServerConfiguration
.
IrmaConfiguration
==
nil
{
var
(
err
error
exists
bool
)
if
conf
.
ServerConfiguration
.
SchemesPath
==
""
{
conf
.
ServerConfiguration
.
SchemesPath
=
irma
.
DefaultSchemesPath
()
// Returns an existing path
}
if
exists
,
err
=
common
.
PathExists
(
conf
.
ServerConfiguration
.
SchemesPath
);
err
!=
nil
{
return
nil
,
server
.
LogError
(
err
)
}
if
!
exists
{
return
nil
,
server
.
LogError
(
errors
.
Errorf
(
"Nonexisting schemes_path provided: %s"
,
conf
.
ServerConfiguration
.
SchemesPath
))
}
conf
.
Logger
.
WithField
(
"schemes_path"
,
conf
.
ServerConfiguration
.
SchemesPath
)
.
Info
(
"Determined schemes path"
)
conf
.
ServerConfiguration
.
IrmaConfiguration
,
err
=
irma
.
NewConfiguration
(
conf
.
ServerConfiguration
.
SchemesPath
,
irma
.
ConfigurationOptions
{
Assets
:
conf
.
ServerConfiguration
.
SchemesAssetsPath
,
})
if
err
!=
nil
{
return
nil
,
server
.
LogError
(
err
)
}
if
err
=
conf
.
ServerConfiguration
.
IrmaConfiguration
.
ParseFolder
();
err
!=
nil
{
return
nil
,
server
.
LogError
(
err
)
}
}
// Setup server urls
if
!
strings
.
HasSuffix
(
conf
.
URL
,
"/"
)
{
conf
.
URL
=
conf
.
URL
+
"/"
}
if
!
strings
.
HasPrefix
(
conf
.
URL
,
"https://"
)
{
if
!
conf
.
Production
||
conf
.
DisableTLS
{
conf
.
DisableTLS
=
true
conf
.
Logger
.
Warnf
(
"TLS is not enabled on the url
\"
%s
\"
to which the IRMA app will connect. "
+
"Ensure that attributes are encrypted in transit by either enabling TLS or adding TLS in a reverse proxy."
,
conf
.
URL
)
}
else
{
return
nil
,
server
.
LogError
(
errors
.
Errorf
(
"Running without TLS in production mode is unsafe without a reverse proxy. "
+
"Either use a https:// URL or explicitly disable TLS."
))
}
}
if
conf
.
ServerConfiguration
.
URL
==
""
{
conf
.
ServerConfiguration
.
URL
=
conf
.
URL
+
"irma/"
conf
.
ServerConfiguration
.
DisableTLS
=
conf
.
DisableTLS
// ensure matching checks
}
// Parse keyshareCore private keys and create a valid keyshare core
core
:=
keyshareCore
.
NewKeyshareCore
()
if
conf
.
JwtPrivateKey
==
""
&&
conf
.
JwtPrivateKeyFile
==
""
{
return
nil
,
server
.
LogError
(
errors
.
Errorf
(
"Missing keyshare server jwt key"
))
}
keybytes
,
err
:=
common
.
ReadKey
(
conf
.
JwtPrivateKey
,
conf
.
JwtPrivateKeyFile
)
if
err
!=
nil
{
return
nil
,
server
.
LogError
(
errors
.
WrapPrefix
(
err
,
"failed to read keyshare server jwt key"
,
0
))
}
jwtPrivateKey
,
err
:=
jwt
.
ParseRSAPrivateKeyFromPEM
(
keybytes
)
if
err
!=
nil
{
return
nil
,
server
.
LogError
(
errors
.
WrapPrefix
(
err
,
"failed to read keyshare server jwt key"
,
0
))
}
core
.
DangerousSetSignKey
(
jwtPrivateKey
)
encId
,
encKey
,
err
:=
readAESKey
(
conf
.
StoragePrimaryKeyFile
)
if
err
!=
nil
{
return
nil
,
server
.
LogError
(
errors
.
WrapPrefix
(
err
,
"failed to load primary storage key"
,
0
))
}
core
.
DangerousSetAESEncryptionKey
(
encId
,
encKey
)
for
_
,
keyFile
:=
range
conf
.
StorageFallbackKeyFiles
{
id
,
key
,
err
:=
readAESKey
(
keyFile
)
if
err
!=
nil
{
return
nil
,
server
.
LogError
(
errors
.
WrapPrefix
(
err
,
"failed to load fallback key "
+
keyFile
,
0
))
}
core
.
DangerousAddAESKey
(
id
,
key
)
}
return
core
,
nil
}
keyshareServerCore/db.go
0 → 100644
View file @
6e9d0360
package
keyshareServerCore
import
(
"errors"
"sync"
"github.com/privacybydesign/irmago/keyshareCore"
)
var
(
ErrUserAlreadyExists
=
errors
.
New
(
"Cannot create user, username already taken"
)
ErrUserNotFound
=
errors
.
New
(
"Could not find specified user"
)
)
type
KeyshareDB
interface
{
NewUser
(
user
KeyshareUser
)
error
User
(
username
string
)
(
KeyshareUser
,
error
)
UpdateUser
(
user
KeyshareUser
)
error
}
type
KeyshareUser
struct
{
Username
string
Coredata
keyshareCore
.
EncryptedKeysharePacket
}
type
keyshareMemoryDB
struct
{
lock
sync
.
Mutex
users
map
[
string
]
keyshareCore
.
EncryptedKeysharePacket
}
func
NewMemoryDatabase
()
KeyshareDB
{
return
&
keyshareMemoryDB
{
users
:
map
[
string
]
keyshareCore
.
EncryptedKeysharePacket
{}}
}
func
(
db
*
keyshareMemoryDB
)
User
(
username
string
)
(
KeyshareUser
,
error
)
{
// Ensure access to database is single-threaded
db
.
lock
.
Lock
()
defer
db
.
lock
.
Unlock
()
// Check and fetch user data
data
,
ok
:=
db
.
users
[
username
]
if
!
ok
{
return
KeyshareUser
{},
ErrUserNotFound
}
return
KeyshareUser
{
Username
:
username
,
Coredata
:
data
},
nil
}
func
(
db
*
keyshareMemoryDB
)
NewUser
(
user
KeyshareUser
)
error
{
// Ensure access to database is single-threaded
db
.
lock
.
Lock
()
defer
db
.
lock
.
Unlock
()
// Check and insert user
_
,
exists
:=
db
.
users
[
user
.
Username
]
if
exists
{
return
ErrUserAlreadyExists
}
db
.
users
[
user
.
Username
]
=
user
.
Coredata
return
nil
}
func
(
db
*
keyshareMemoryDB
)
UpdateUser
(
user
KeyshareUser
)
error
{
// Ensure access to database is single-threaded
db
.
lock
.
Lock
()
defer
db
.
lock
.
Unlock
()
// Check and update user.
_
,
exists
:=
db
.
users
[
user
.
Username
]
if
exists
{
return
ErrUserNotFound
}
db
.
users
[
user
.
Username
]
=
user
.
Coredata
return
nil
}
keyshareServerCore/messages.go
0 → 100644
View file @
6e9d0360
package
keyshareServerCore
import
(
"github.com/privacybydesign/gabi"
)
type
keyshareEnrollment
struct
{
Username
string
`json:"username"`
Pin
string
`json:"pin"`
Email
*
string
`json:"email"`
Language
string
`json:"language"`
}
type
keyshareChangepin
struct
{
Username
string
`json:"id"`
OldPin
string
`json:"oldpin"`
NewPin
string
`json:"newpin"`
}
type
keyshareAuthorization
struct
{
Status
string
`json:"status"`
Candidates
[]
string
`json:"candidates"`
}
type
keysharePinMessage
struct
{
Username
string
`json:"id"`
Pin
string
`json:"pin"`
}
type
keysharePinStatus
struct
{
Status
string
`json:"status"`
Message
string
`json:"message"`
}
type
proofPCommitmentMap
struct
{
Commitments
map
[
string
]
*
gabi
.
ProofPCommitment
`json:"c"`
}
keyshareServerCore/server.go
0 → 100644
View file @
6e9d0360
package
keyshareServerCore
import
(
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big"
irma
"github.com/privacybydesign/irmago"
"github.com/sirupsen/logrus"
"github.com/privacybydesign/irmago/keyshareCore"
"github.com/privacybydesign/irmago/server"
"github.com/privacybydesign/irmago/server/irmaserver"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)
type
SessionData
struct
{
LastKeyid
irma
.
PublicKeyIdentifier
LastCommitID
uint64
}
type
Server
struct
{
conf
*
Configuration
core
*
keyshareCore
.
KeyshareCore
sessionserver
*
irmaserver
.
Server
db
KeyshareDB
sessions
map
[
string
]
*
SessionData
sessionLock
sync
.
Mutex
}
func
New
(
conf
*
Configuration
)
(
*
Server
,
error
)
{
var
err
error
s
:=
&
Server
{
conf
:
conf
,
sessions
:
map
[
string
]
*
SessionData
{},
}
// Do initial processing of configuration and create keyshare core
s
.
core
,
err
=
processConfiguration
(
conf
)
if
err
!=
nil
{
return
nil
,
err
}
// Load neccessary idemix keys into core, and ensure that future updates
// to them are processed
s
.
LoadIdemixKeys
(
conf
.
ServerConfiguration
.
IrmaConfiguration
)
conf
.
ServerConfiguration
.
IrmaConfiguration
.
UpdateListeners
=
append
(
conf
.
ServerConfiguration
.
IrmaConfiguration
.
UpdateListeners
,
s
.
LoadIdemixKeys
)
// Setup irma session server
s
.
sessionserver
,
err
=
irmaserver
.
New
(
conf
.
ServerConfiguration
)
if
err
!=
nil
{
return
nil
,
err
}
// Setup DB (TODO: make configurable)
s
.
db
=
NewMemoryDatabase
()
return
s
,
nil
}
func
(
s
*
Server
)
Handler
()
http
.
Handler
{
router
:=
chi
.
NewRouter
()
router
.
Use
(
middleware
.
Logger
)
router
.
Post
(
"/api/v1/client/register"
,
s
.
handleRegister
)
router
.
Post
(
"/api/v1/users/isAuthorized"
,
s
.
handleValidate
)
router
.
Post
(
"/api/v1/users/verify/pin"
,
s
.
handleVerifyPin
)
router
.
Post
(
"/api/v1/prove/getCommitments"
,
s
.
handleCommitments
)
router
.
Post
(
"/api/v1/prove/getResponse"
,
s
.
handleResponse
)
router
.
Mount
(
"/irma/"
,
s
.
sessionserver
.
HandlerFunc
())
return
router
}
func
(
s
*
Server
)
LoadIdemixKeys
(
conf
*
irma
.
Configuration
)
{
fmt
.
Println
(
"load called"
)
for
_
,
issuer
:=
range
conf
.
Issuers
{
keyIds
,
err
:=
conf
.
PublicKeyIndices
(
issuer
.
Identifier
())
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"issuer"
:
issuer
,
"error"
:
err
})
.
Warn
(
"Could not find key ids for issuer"
)
continue
}
for
_
,
id
:=
range
keyIds
{
key
,
err
:=
conf
.
PublicKey
(
issuer
.
Identifier
(),
id
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"keyid"
:
id
,
"error"
:
err
})
.
Warn
(
"Could not fetch public key for issuer"
)
continue
}
s
.
core
.
DangerousAddTrustedPublicKey
(
irma
.
PublicKeyIdentifier
{
Issuer
:
issuer
.
Identifier
(),
Counter
:
uint
(
id
)},
key
)
}
}
}
func
(
s
*
Server
)
handleCommitments
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
// Read keys
body
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Info
(
"Malformed request: could not read request body"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
fmt
.
Println
(
string
(
body
))
var
keys
[]
irma
.
PublicKeyIdentifier
err
=
json
.
Unmarshal
(
body
,
&
keys
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Info
(
"Malformed request: could not parse request body"
)
s
.
conf
.
Logger
.
WithField
(
"body"
,
body
)
.
Debug
(
"Malformed request data"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
if
len
(
keys
)
==
0
{
s
.
conf
.
Logger
.
Info
(
"Malformed request: no keys over which to commit specified"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
"No key specified"
)
return
}
// Extract username and authorization from request
username
:=
r
.
Header
.
Get
(
"X-IRMA-Keyshare-Username"
)
authorization
:=
r
.
Header
.
Get
(
"Authorization"
)
user
,
err
:=
s
.
db
.
User
(
username
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"username"
:
username
,
"error"
:
err
})
.
Warn
(
"User not found in db"
)
server
.
WriteError
(
w
,
server
.
ErrorUserNotRegistered
,
err
.
Error
())
return
}
// TODO: block check
commitments
,
commitId
,
err
:=
s
.
core
.
GenerateCommitments
(
user
.
Coredata
,
authorization
,
keys
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Warn
(
"Could not generate commitments for request"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
// Prepare output message format
mappedCommitments
:=
map
[
string
]
*
gabi
.
ProofPCommitment
{}
for
i
,
keyid
:=
range
keys
{
keyidV
,
err
:=
keyid
.
MarshalText
()
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"keyid"
:
keyid
,
"error"
:
err
})
.
Error
(
"Could not convert key identifier to string"
)
server
.
WriteError
(
w
,
server
.
ErrorInternal
,
err
.
Error
())
return
}
mappedCommitments
[
string
(
keyidV
)]
=
commitments
[
i
]
}
// Store needed data for later requests.
s
.
sessionLock
.
Lock
()
if
_
,
ok
:=
s
.
sessions
[
username
];
!
ok
{
s
.
sessions
[
username
]
=
&
SessionData
{}
}
s
.
sessions
[
username
]
.
LastCommitID
=
commitId
s
.
sessions
[
username
]
.
LastKeyid
=
keys
[
0
]
s
.
sessionLock
.
Unlock
()
// And send response
server
.
WriteJson
(
w
,
proofPCommitmentMap
{
Commitments
:
mappedCommitments
})
}
func
(
s
*
Server
)
handleResponse
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
// Read challenge
body
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Info
(
"Malformed request: could not read request body"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
challenge
:=
new
(
big
.
Int
)
err
=
json
.
Unmarshal
(
body
,
challenge
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
Info
(
"Malformed request: could not parse challenge"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
// Extract username and authorization from request
username
:=
r
.
Header
.
Get
(
"X-IRMA-Keyshare-Username"
)
authorization
:=
r
.
Header
.
Get
(
"Authorization"
)
// Fetch user
user
,
err
:=
s
.
db
.
User
(
username
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"username"
:
username
,
"error"
:
err
})
.
Warn
(
"Could not find user in db"
)
server
.
WriteError
(
w
,
server
.
ErrorUserNotRegistered
,
err
.
Error
())
return
}
// verify access (avoids leaking information to unauthorized callers)
err
=
s
.
core
.
ValidateJWT
(
user
.
Coredata
,
authorization
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Warn
(
"Could not generate keyshare response"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
// Get data from session
s
.
sessionLock
.
Lock
()
sessionData
,
ok
:=
s
.
sessions
[
username
]
s
.
sessionLock
.
Unlock
()
if
!
ok
{
s
.
conf
.
Logger
.
Warn
(
"Request for response without previous call to get commitments"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
"Missing previous call to getCommitments"
)
return
}
proofResponse
,
err
:=
s
.
core
.
GenerateResponse
(
user
.
Coredata
,
authorization
,
sessionData
.
LastCommitID
,
challenge
,
sessionData
.
LastKeyid
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Error
(
"Could not generate response for request"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
server
.
WriteString
(
w
,
proofResponse
)
}
func
(
s
*
Server
)
handleValidate
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
// Extract username and authorization from request
username
:=
r
.
Header
.
Get
(
"X-IRMA-Keyshare-Username"
)
authorization
:=
r
.
Header
.
Get
(
"Authorization"
)
user
,
err
:=
s
.
db
.
User
(
username
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithFields
(
logrus
.
Fields
{
"username"
:
username
,
"error"
:
err
})
.
Warn
(
"Could not find user in db"
)
server
.
WriteError
(
w
,
server
.
ErrorUserNotRegistered
,
err
.
Error
())
return
}
// TODO: Block check
err
=
s
.
core
.
ValidateJWT
(
user
.
Coredata
,
authorization
)
if
err
!=
nil
{
server
.
WriteJson
(
w
,
&
keyshareAuthorization
{
Status
:
"expired"
,
Candidates
:
[]
string
{
"pin"
}})
}
else
{
server
.
WriteJson
(
w
,
&
keyshareAuthorization
{
Status
:
"authorized"
,
Candidates
:
[]
string
{
"pin"
}})
}
}
func
(
s
*
Server
)
handleVerifyPin
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
// Extract request
body
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
if
err
!=
nil
{
s
.
conf
.
Logger
.
WithField
(
"error"
,
err
)
.
Info
(
"Malformed request: could not read request body"
)
server
.
WriteError
(
w
,
server
.
ErrorInvalidRequest
,
err
.
Error
())
return
}
var
msg
keysharePinMessage
err
=
json
.
Unmarshal