1module User.Layer.Methods.RemoteStorage exposing (Attributes, oauthAddress, parseUserAddress, userAddressError, webfingerAddress, webfingerDecoder, webfingerError, webfingerRequest)
2
3import Base64
4import Http
5import Json.Decode as Decode exposing (Decoder)
6import Url
7import UrlBase64
8
9
10
11-- 🌳
12
13
14type alias Attributes =
15 { host : String
16 , username : String
17 }
18
19
20userAddressError =
21 "Please provide a valid RemoteStorage address, the format is **user@server**"
22
23
24webfingerError =
25 "**Failed to connect** to the given RemoteStorage server, maybe a typo?"
26
27
28
29-- 🔱
30
31
32parseUserAddress : String -> Maybe Attributes
33parseUserAddress str =
34 case String.split "@" str of
35 [ u, h ] ->
36 Just { host = h, username = u }
37
38 _ ->
39 Nothing
40
41
42oauthAddress : { oauthOrigin : String, origin : String } -> Attributes -> String
43oauthAddress { oauthOrigin, origin } { host, username } =
44 let
45 hostWithoutProtocol =
46 host
47 |> String.split "://"
48 |> List.drop 1
49 |> List.head
50 |> Maybe.withDefault host
51
52 ua =
53 (username ++ "@" ++ hostWithoutProtocol)
54 |> UrlBase64.encode (Base64.encode >> Ok)
55 |> Result.withDefault "BASE64_ENCODING_FAILED"
56 in
57 String.concat
58 [ oauthOrigin
59 , "?redirect_uri=" ++ Url.percentEncode (origin ++ "?action=authenticate/remotestorage/" ++ ua)
60 , "&client_id=" ++ Url.percentEncode origin
61 , "&scope=" ++ Url.percentEncode "diffuse:rw"
62 , "&response_type=token"
63 ]
64
65
66webfingerAddress : Url.Protocol -> Attributes -> String
67webfingerAddress originProtocol { host, username } =
68 let
69 fallbackProtocol =
70 case originProtocol of
71 Url.Http ->
72 "http"
73
74 Url.Https ->
75 "https"
76
77 protocol =
78 if String.contains "://" host then
79 host
80 |> String.split "://"
81 |> List.head
82 |> Maybe.withDefault fallbackProtocol
83
84 else
85 fallbackProtocol
86
87 hostWithoutProtocol =
88 host
89 |> String.split "://"
90 |> List.drop 1
91 |> List.head
92 |> Maybe.withDefault host
93 in
94 protocol ++ "://" ++ hostWithoutProtocol ++ "/.well-known/webfinger?resource=acct:" ++ Url.percentEncode (username ++ "@" ++ hostWithoutProtocol)
95
96
97webfingerDecoder : Decoder String
98webfingerDecoder =
99 Decode.at
100 [ "links"
101 , "0"
102 , "properties"
103 , "http://tools.ietf.org/html/rfc6749#section-4.2"
104 ]
105 Decode.string
106
107
108webfingerRequest : (Attributes -> Result Http.Error String -> msg) -> Url.Protocol -> Attributes -> Cmd msg
109webfingerRequest toMsg originProtocol rs =
110 Http.get
111 { url = webfingerAddress originProtocol rs
112 , expect = Http.expectJson (toMsg rs) webfingerDecoder
113 }