summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--main/Main.hs41
2 files changed, 53 insertions, 1 deletions
diff --git a/README.md b/README.md
index 28b203d..a84a3aa 100644
--- a/README.md
+++ b/README.md
@@ -150,7 +150,7 @@ are signed, so message author can not be forged.
history, but the chatroom will no longer be listed as available and no futher
updates for this chatroom will be collected or shared with other peers.
-### Add contacts
+### Contact list
To ensure the identity of the contact and prevent man-in-the-middle attack,
generated verification code needs to be confirmed on both devices to add
@@ -175,6 +175,17 @@ new contact, list peers using `/peers` command and select one with `/<number>`.
`/contact-reject`
: Reject contact request or verification code of selected peer.
+`/invite-contact <name>`
+: Create an invite in the form of URL, which can be sent via means outside of
+ the erebos protocol. The recipient can accept it using the `invite-accept`
+ command. After accepting, contact entry is created with the given `<name>`.
+ The created invite can be used only once.
+
+`/invite-accept <URL>`
+: Accept received URL-formatted invite. The erebos tool will try to find and
+ connect to a device belonging to the issuing identity to confirm the invite.
+ If successful, corresponding contact entry will be created.
+
### Attach other devices
Multiple devices can be attached to single identity to be used by the same
diff --git a/main/Main.hs b/main/Main.hs
index c1f30f2..227451f 100644
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -623,6 +623,8 @@ commands =
, ( "contact-add", cmdContactAdd )
, ( "contact-accept", cmdContactAccept )
, ( "contact-reject", cmdContactReject )
+ , ( "invite-contact", cmdInviteContact )
+ , ( "invite-accept", cmdInviteAccept )
, ( "conversations", cmdConversations )
, ( "new", cmdNew )
, ( "details", cmdDetails )
@@ -955,6 +957,45 @@ cmdContactAccept = contactAccept =<< getSelectedPeer
cmdContactReject :: Command
cmdContactReject = contactReject =<< getSelectedPeer
+cmdInviteContact :: Command
+cmdInviteContact = do
+ term <- asks ciTerminal
+ name <- asks ciLine >>= \case
+ line | not (null line) -> return $ T.pack line
+ _ -> liftIO $ do
+ setPrompt term "Name: "
+ getInputLine term $ KeepPrompt . maybe T.empty T.pack
+ (lookupSharedValue . lsShared . fromStored <$> getLocalHead) >>= \case
+ Just (self :: ComposedIdentity) -> do
+ invite <- createSingleContactInvite name
+ dgst : _ <- return $ refDigest . storedRef <$> idDataF self
+ cmdPutStrLn $ "https://app.erebosprotocol.net/#inv" <> (maybe "" (("=" <>) . showInviteToken) (inviteToken invite)) <> "&from=blake2%23" <> drop 7 (show dgst)
+ Nothing -> do
+ throwOtherError "no shared identity"
+
+cmdInviteAccept :: Command
+cmdInviteAccept = do
+ term <- asks ciTerminal
+ url <- asks ciLine >>= \case
+ line | not (null line) -> return $ T.pack line
+ _ -> liftIO $ do
+ setPrompt term "URL: "
+ getInputLine term $ KeepPrompt . maybe T.empty T.pack
+ case T.breakOn "://" url of
+ ( proto, url' )
+ | proto `elem` [ "http", "https" ]
+ , ( _, url'' ) <- T.breakOn "#" url'
+ , Just ( '#', params ) <- T.uncons url''
+ , [ pfrom, pinv ] <- sort $ T.splitOn "&" params
+ , ( nfrom, tfrom ) <- T.splitAt 14 pfrom, nfrom == "from=blake2%23"
+ , ( ninv, tinv ) <- T.splitAt 4 pinv, ninv == "inv="
+ , Just from <- readRefDigest $ T.encodeUtf8 $ "blake2#" <> tfrom
+ , Just token <- parseInviteToken tinv
+ -> do
+ server <- asks ciServer
+ acceptInvite server from token
+ _ -> throwOtherError "invalit invite URL"
+
cmdConversations :: Command
cmdConversations = do
conversations <- lookupConversations