2016-03-08 11:52:46 +09:00
|
|
|
{- This file is part of Vervis.
|
|
|
|
-
|
|
|
|
- Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
|
|
|
|
-
|
|
|
|
- ♡ Copying is an act of love. Please copy, reuse and share.
|
|
|
|
-
|
|
|
|
- The author(s) have dedicated all copyright and related and neighboring
|
|
|
|
- rights to this software to the public domain worldwide. This software is
|
|
|
|
- distributed without any warranty.
|
|
|
|
-
|
|
|
|
- You should have received a copy of the CC0 Public Domain Dedication along
|
|
|
|
- with this software. If not, see
|
|
|
|
- <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
-}
|
|
|
|
|
|
|
|
module Vervis.Field.Key
|
|
|
|
( nameField
|
|
|
|
, algoField
|
|
|
|
, contentField
|
|
|
|
)
|
|
|
|
where
|
|
|
|
|
|
|
|
import Prelude
|
|
|
|
|
|
|
|
import Data.ByteString (ByteString)
|
2016-03-08 12:38:32 +09:00
|
|
|
import Data.ByteString.Base64 (decode)
|
2016-03-08 11:52:46 +09:00
|
|
|
import Data.Char (isDigit)
|
|
|
|
import Data.Maybe (isNothing)
|
|
|
|
import Data.Text (Text)
|
|
|
|
import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
|
|
|
|
import Data.Text.Encoding.Error (lenientDecode)
|
|
|
|
import Database.Persist (checkUnique)
|
|
|
|
import Yesod.Form.Fields (textField)
|
2016-03-08 12:38:32 +09:00
|
|
|
import Yesod.Form.Functions (check, checkBool, checkM, convertField)
|
2016-03-08 11:52:46 +09:00
|
|
|
import Yesod.Form.Types (Field)
|
|
|
|
import Yesod.Persist.Core (runDB)
|
|
|
|
|
2016-03-08 12:38:32 +09:00
|
|
|
import qualified Data.ByteString.Char8 as BC
|
2016-03-08 11:52:46 +09:00
|
|
|
import qualified Data.Text as T
|
|
|
|
|
|
|
|
import Data.Char.Local (isAsciiLetter)
|
|
|
|
import Network.SSH.Local (supportedKeyAlgos)
|
|
|
|
import Vervis.Foundation
|
|
|
|
import Vervis.Model
|
|
|
|
|
|
|
|
mkBsField :: Field Handler Text -> Field Handler ByteString
|
|
|
|
mkBsField = convertField encodeUtf8 (decodeUtf8With lenientDecode)
|
|
|
|
|
|
|
|
bsField :: Field Handler ByteString
|
|
|
|
bsField = mkBsField textField
|
|
|
|
|
|
|
|
checkNameUnique :: PersonId -> Field Handler Text -> Field Handler Text
|
|
|
|
checkNameUnique pid = checkM $ \ name -> runDB $ do
|
|
|
|
let key = SshKey
|
|
|
|
{ sshKeyPerson = pid
|
|
|
|
, sshKeyName = name
|
|
|
|
, sshKeyAlgo = mempty
|
|
|
|
, sshKeyContent = mempty
|
|
|
|
}
|
|
|
|
muk <- checkUnique key
|
|
|
|
return $ if isNothing muk
|
|
|
|
then Right name
|
|
|
|
else Left ("You already have a key with this label" :: Text)
|
|
|
|
|
|
|
|
nameField :: PersonId -> Field Handler Text
|
|
|
|
nameField pid = checkNameUnique pid textField
|
|
|
|
|
|
|
|
checkAlgoSupported :: Field Handler ByteString -> Field Handler ByteString
|
|
|
|
checkAlgoSupported =
|
|
|
|
let ok = (`elem` supportedKeyAlgos)
|
|
|
|
msg :: Text
|
|
|
|
msg = "This algorithm isn't supported"
|
|
|
|
in checkBool ok msg
|
|
|
|
|
|
|
|
algoField :: Field Handler ByteString
|
|
|
|
algoField = checkAlgoSupported bsField
|
|
|
|
|
2016-03-08 12:38:32 +09:00
|
|
|
checkContent :: Field Handler ByteString -> Field Handler ByteString
|
2016-03-08 11:52:46 +09:00
|
|
|
checkContent =
|
2016-03-08 12:38:32 +09:00
|
|
|
{-let lasts = (== '=')
|
2016-03-08 11:52:46 +09:00
|
|
|
rest c = isAsciiLetter c || isDigit c || c == '+' || c == '/'
|
2016-03-08 12:38:32 +09:00
|
|
|
ok b = BC.all rest $ BC.dropWhileEnd lasts b
|
2016-03-08 11:52:46 +09:00
|
|
|
msg :: Text
|
2016-03-08 12:38:32 +09:00
|
|
|
msg = "Must be a base64-encoded public SSH key"-}
|
|
|
|
check $ \ t ->
|
|
|
|
case decode t of
|
|
|
|
Left s -> Left $ T.pack s
|
|
|
|
Right b -> Right b
|
|
|
|
|
|
|
|
--TODO make the above work over ByteString and when passes the check, apply
|
|
|
|
--base64 conversion. delete my rel4 key from the DB and re-insert...
|
2016-03-08 11:52:46 +09:00
|
|
|
|
|
|
|
contentField :: Field Handler ByteString
|
2016-03-08 12:38:32 +09:00
|
|
|
contentField = checkContent bsField
|