2016-02-18 01:43:23 +09:00
|
|
|
{- This file is part of Vervis.
|
|
|
|
-
|
2019-01-19 14:56:58 +09:00
|
|
|
- Written in 2016, 2018, 2019 by fr33domlover <fr33domlover@riseup.net>.
|
2016-02-18 01:43:23 +09:00
|
|
|
-
|
|
|
|
- ♡ 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/>.
|
|
|
|
-}
|
|
|
|
|
2016-02-23 17:45:03 +09:00
|
|
|
module Vervis.Handler.Person
|
2018-03-18 07:16:02 +09:00
|
|
|
( getResendVerifyEmailR
|
|
|
|
, getPeopleR
|
2019-02-15 07:13:58 +09:00
|
|
|
, getPerson
|
2016-02-18 01:43:23 +09:00
|
|
|
)
|
|
|
|
where
|
|
|
|
|
2016-02-23 17:45:03 +09:00
|
|
|
import Vervis.Import hiding ((==.))
|
2016-02-18 01:43:23 +09:00
|
|
|
--import Prelude
|
|
|
|
|
2019-02-24 10:21:42 +09:00
|
|
|
import Data.List.NonEmpty (NonEmpty (..))
|
2016-07-28 06:46:48 +09:00
|
|
|
import Database.Esqueleto hiding (isNothing, count)
|
2016-02-25 12:10:30 +09:00
|
|
|
import Vervis.Form.Person
|
2016-02-18 01:43:23 +09:00
|
|
|
--import Model
|
2016-03-07 09:39:07 +09:00
|
|
|
import Text.Blaze.Html (toHtml)
|
2018-03-18 07:16:02 +09:00
|
|
|
import Yesod.Auth.Account (newAccountR, resendVerifyEmailWidget, username)
|
|
|
|
import Yesod.Auth.Account.Message (AccountMsg (MsgEmailUnverified))
|
|
|
|
|
2019-01-19 14:56:58 +09:00
|
|
|
import qualified Data.Text as T (unpack)
|
|
|
|
|
2018-03-18 07:16:02 +09:00
|
|
|
import Yesod.Auth.Unverified (requireUnverifiedAuth)
|
2016-02-18 01:43:23 +09:00
|
|
|
|
2018-03-06 11:26:27 +09:00
|
|
|
import Text.Email.Local
|
|
|
|
|
2019-02-08 08:08:28 +09:00
|
|
|
import Network.FedURI
|
2019-01-22 00:54:57 +09:00
|
|
|
import Web.ActivityPub
|
|
|
|
|
2019-01-19 14:56:58 +09:00
|
|
|
--import Vervis.ActivityStreams
|
|
|
|
import Vervis.ActorKey
|
2016-05-24 05:46:54 +09:00
|
|
|
import Vervis.Model.Ident
|
2018-03-06 09:55:52 +09:00
|
|
|
import Vervis.Secure
|
2016-05-26 06:10:41 +09:00
|
|
|
import Vervis.Widget (avatarW)
|
2016-05-24 05:46:54 +09:00
|
|
|
|
2018-03-18 07:16:02 +09:00
|
|
|
-- | Account verification email resend form
|
|
|
|
getResendVerifyEmailR :: Handler Html
|
|
|
|
getResendVerifyEmailR = do
|
|
|
|
person <- requireUnverifiedAuth
|
|
|
|
defaultLayout $ do
|
|
|
|
setTitleI MsgEmailUnverified
|
|
|
|
[whamlet|
|
|
|
|
<p>_{MsgEmailUnverified}
|
|
|
|
^{resendVerifyEmailWidget (username person) AuthR}
|
|
|
|
|]
|
|
|
|
|
2016-02-19 13:10:42 +09:00
|
|
|
-- | Get list of users
|
2016-02-18 01:43:23 +09:00
|
|
|
getPeopleR :: Handler Html
|
|
|
|
getPeopleR = do
|
|
|
|
people <- runDB $ select $ from $ \ (sharer, person) -> do
|
|
|
|
where_ $ sharer ^. SharerId ==. person ^. PersonIdent
|
|
|
|
orderBy [asc $ sharer ^. SharerIdent]
|
|
|
|
return $ sharer ^. SharerIdent
|
2016-05-24 05:46:54 +09:00
|
|
|
defaultLayout $(widgetFile "people")
|
2016-02-18 01:43:23 +09:00
|
|
|
|
2019-02-15 07:13:58 +09:00
|
|
|
{-
|
2016-02-19 13:10:42 +09:00
|
|
|
-- | Create new user
|
2016-02-23 11:27:01 +09:00
|
|
|
postPeopleR :: Handler Html
|
2018-03-04 06:33:59 +09:00
|
|
|
postPeopleR = redirect $ AuthR newAccountR
|
2016-07-28 06:46:48 +09:00
|
|
|
settings <- getsYesod appSettings
|
|
|
|
if appRegister settings
|
2016-04-20 01:03:27 +09:00
|
|
|
then do
|
2016-07-28 06:46:48 +09:00
|
|
|
room <- case appAccounts settings of
|
|
|
|
Nothing -> return True
|
|
|
|
Just cap -> do
|
|
|
|
current <- runDB $ count ([] :: [Filter Person])
|
|
|
|
return $ current < cap
|
|
|
|
if room
|
|
|
|
then do
|
|
|
|
((result, widget), enctype) <- runFormPost newPersonForm
|
|
|
|
case result of
|
|
|
|
FormSuccess np -> do
|
|
|
|
now <- liftIO getCurrentTime
|
|
|
|
runDB $ do
|
|
|
|
let sharer = Sharer
|
|
|
|
{ sharerIdent = npLogin np
|
|
|
|
, sharerName = npName np
|
|
|
|
, sharerCreated = now
|
|
|
|
}
|
|
|
|
sid <- insert sharer
|
|
|
|
let person = Person
|
|
|
|
{ personIdent = sid
|
|
|
|
, personLogin = shr2text $ npLogin np
|
|
|
|
, personHash = Nothing
|
|
|
|
, personEmail = npEmail np
|
|
|
|
}
|
|
|
|
person' <- setPassword (npPass np) person
|
|
|
|
insert_ person'
|
|
|
|
redirectUltDest HomeR
|
|
|
|
FormMissing -> do
|
|
|
|
setMessage "Field(s) missing"
|
|
|
|
defaultLayout $(widgetFile "person-new")
|
|
|
|
FormFailure _l -> do
|
|
|
|
setMessage
|
|
|
|
"User registration failed, see errors below"
|
|
|
|
defaultLayout $(widgetFile "person-new")
|
|
|
|
else do
|
|
|
|
setMessage "Maximal number of registered users reached"
|
|
|
|
redirect PeopleR
|
|
|
|
else do
|
|
|
|
setMessage "User registration disabled"
|
|
|
|
redirect PeopleR
|
2018-03-04 06:33:59 +09:00
|
|
|
-}
|
2016-02-19 13:10:42 +09:00
|
|
|
|
2019-02-15 07:13:58 +09:00
|
|
|
{-
|
2016-02-19 13:10:42 +09:00
|
|
|
getPersonNewR :: Handler Html
|
2018-03-04 06:33:59 +09:00
|
|
|
getPersonNewR = redirect $ AuthR newAccountR
|
2016-05-25 06:48:21 +09:00
|
|
|
regEnabled <- getsYesod $ appRegister . appSettings
|
|
|
|
if regEnabled
|
|
|
|
then do
|
|
|
|
((_result, widget), enctype) <- runFormPost newPersonForm
|
|
|
|
defaultLayout $(widgetFile "person-new")
|
|
|
|
else notFound
|
2018-03-04 06:33:59 +09:00
|
|
|
-}
|
2016-02-19 13:10:42 +09:00
|
|
|
|
2019-02-15 07:13:58 +09:00
|
|
|
getPerson :: ShrIdent -> Person -> Handler TypedContent
|
|
|
|
getPerson shr person = do
|
2019-01-19 14:56:58 +09:00
|
|
|
renderUrl <- getUrlRender
|
|
|
|
let route2uri route =
|
2019-02-08 08:08:28 +09:00
|
|
|
case parseFedURI $ renderUrl route of
|
|
|
|
Left e -> error $ "getRenderUrl produced invalid FedURI!!! " ++ e
|
|
|
|
Right u -> u
|
2019-02-22 08:59:53 +09:00
|
|
|
route2local = snd . f2l . route2uri
|
|
|
|
(host, me) = f2l $ route2uri $ SharerR shr
|
2018-03-26 04:26:30 +09:00
|
|
|
selectRep $ do
|
|
|
|
provideRep $ do
|
|
|
|
secure <- getSecure
|
|
|
|
defaultLayout $(widgetFile "person")
|
2019-02-22 08:59:53 +09:00
|
|
|
provideAP $ Doc host Actor
|
Support remote actors specifying 2 keys, and DB storage of these keys
It's now possible for activities we be attributed to actors that have more than
one key. We allow up to 2 keys. We also store in the DB. Scaling to support any
number of keys is trivial, but I'm limiting to 2 to avoid potential trouble and
because 2 is the actual number we need.
By having 2 keys, and replacing only one of them in each rotation, we avoid
race conditions. With 1 key, the following can happen:
1. We send an activity to another server
2. We rotate our key
3. The server reaches the activity in its processing queue, tries to verify our
request signature, but fails because it can't fetch the key. It's the old
key and we discarded it already, replaced it with the new one
When we use 2 keys, the previous key remains available and other servers have
time to finish processing our requests signed with that key. We can safely
rotate, without worrying about whether the user sent anything right before the
rotation time.
Caveat: With this feature, we allow OTHER servers to rotate freely. It's safe
because it's optional, but it's just Vervis right now. Once Vervis itself
starts using 2 keys, it will be able to rotate freely without race condition
risk, but probably Mastodon etc. won't accept its signatures because of the use
of 2 keys and because they're server-scope keys.
Maybe I can get these features adopted by the fediverse?
2019-02-05 04:38:50 +09:00
|
|
|
{ actorId = me
|
|
|
|
, actorType = ActorTypePerson
|
|
|
|
, actorUsername = shr2text shr
|
2019-02-22 08:59:53 +09:00
|
|
|
, actorInbox = route2local InboxR
|
2019-02-24 10:21:42 +09:00
|
|
|
, actorPublicKeys =
|
2019-03-20 18:31:08 +09:00
|
|
|
[ Left $ route2local ActorKey1R
|
|
|
|
, Left $ route2local ActorKey2R
|
|
|
|
]
|
2019-01-19 14:56:58 +09:00
|
|
|
}
|