A music player that connects to your cloud/distributed storage.
1module Sources.Services.Azure.Authorization exposing (Computation(..), SignatureDependencies, StorageMethod(..), makeSignature, presignedUrl)
2
3{-| Resources:
4
5 - <https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas#account-sas-example>
6 - <https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-a-Service-SAS?redirectedfrom=MSDN>
7
8-}
9
10import Binary
11import BinaryBase64
12import Common
13import Cryptography.Hmac as Hmac
14import DateFormat as Date
15import Dict.Ext as Dict
16import SHA
17import Sources exposing (SourceData)
18import Sources.Processing exposing (HttpMethod)
19import String.Ext as String
20import Time
21import Url
22
23
24
25-- Types
26
27
28type Computation
29 = List
30 | Read
31
32
33type StorageMethod
34 = Blob
35 | File
36
37
38
39-- Public functions
40
41
42presignedUrl :
43 StorageMethod
44 -> Computation
45 -> HttpMethod
46 -> Int
47 -> Time.Posix
48 -> SourceData
49 -> String
50 -> List ( String, String )
51 -> String
52presignedUrl storageMethod computation _ _ currentTime srcData pathToFile params =
53 let
54 azure =
55 srcData
56
57 accountName =
58 Dict.fetchUnknown "accountName" azure
59
60 accountKey =
61 Dict.fetchUnknown "accountKey" azure
62
63 container =
64 Dict.fetchUnknown "container" azure
65
66 -- {var} Time (y-MM-ddTHH:mmZ)
67 expiryTime =
68 Date.format
69 [ Date.yearNumber
70 , Date.text "-"
71 , Date.monthFixed
72 , Date.text "-"
73 , Date.dayOfMonthFixed
74 , Date.text "T"
75 , Date.hourMilitaryFixed
76 , Date.text ":"
77 , Date.minuteFixed
78 , Date.text "Z"
79 ]
80 Time.utc
81 (currentTime
82 |> Time.posixToMillis
83 |> (+) 3600000
84 |> Time.millisToPosix
85 )
86
87 -- {var} Other
88 permissions =
89 case computation of
90 List ->
91 "l"
92
93 Read ->
94 "r"
95
96 resourceType =
97 case storageMethod of
98 Blob ->
99 "blob"
100
101 File ->
102 "file"
103
104 resType =
105 case storageMethod of
106 Blob ->
107 "container"
108
109 File ->
110 "directory"
111
112 -- Signature
113 signatureStuff =
114 { accountKey = accountKey
115 , accountName = accountName
116 , expiryTime = expiryTime
117 , permissions = permissions
118 , protocol = "https"
119 , resources = "co"
120 , services = "bf"
121 , startTime = ""
122 , version = "2017-04-17"
123 }
124 in
125 String.concat
126 [ "https://"
127 , Url.percentEncode accountName
128 , "."
129 , Url.percentEncode resourceType
130 , ".core.windows.net/"
131 , Url.percentEncode container
132 , "/"
133 , Url.percentEncode (String.chopStart "/" pathToFile)
134
135 -- Start query params
136 , case Common.queryString params of
137 "" ->
138 "?"
139
140 qs ->
141 qs
142
143 -- Query params for certain requests
144 , case computation of
145 List ->
146 "&restype=" ++ resType ++ "&comp=list"
147
148 _ ->
149 ""
150
151 -- Signature things
152 , "&sv="
153 , Url.percentEncode signatureStuff.version
154 , "&ss="
155 , Url.percentEncode signatureStuff.services
156 , "&srt="
157 , Url.percentEncode signatureStuff.resources
158 , "&sp="
159 , Url.percentEncode signatureStuff.permissions
160 , "&se="
161 , Url.percentEncode signatureStuff.expiryTime
162 , "&spr="
163 , Url.percentEncode signatureStuff.protocol
164 , "&sig="
165 , Url.percentEncode (makeSignature signatureStuff)
166 ]
167
168
169
170-- Signature
171
172
173type alias SignatureDependencies =
174 { accountKey : String
175 , accountName : String
176 , expiryTime : String
177 , permissions : String
178 , protocol : String
179 , resources : String
180 , services : String
181 , startTime : String
182 , version : String
183 }
184
185
186{-| Make a signature.
187
188 >>> makeSignature { accountKey = "93K17Co74T2lDHk2rA+wmb/avIAS6u6lPnZrk2hyT+9+aov82qNhrcXSNGZCzm9mjd4d75/oxxOr6r1JVpgTLA==", accountName = "tsmatsuzsttest0001", expiryTime = "2016-07-08T04:41:20Z", permissions = "rwdlacup", protocol = "https", resources = "sco", services = "bfqt", startTime = "2016-06-29T04:41:20Z", version = "2015-04-05" }
189 "+XuDjuLE1Sv/FrJTLz8YjsaDukWNTKX7e8G8Ew+5aps="
190
191-}
192makeSignature : SignatureDependencies -> String
193makeSignature { accountKey, accountName, expiryTime, permissions, protocol, resources, services, startTime, version } =
194 let
195 message =
196 -- accountname + "\n" +
197 -- signedpermissions + "\n" +
198 -- signedservice + "\n" +
199 -- signedresourcetype + "\n" +
200 -- signedstart + "\n" +
201 -- signedexpiry + "\n" +
202 -- signedIP + "\n" +
203 -- signedProtocol + "\n" +
204 -- signedversion + "\n"
205 String.join "\n"
206 [ accountName
207 , permissions
208 , services
209 , resources
210 , startTime
211 , expiryTime
212 , ""
213 , protocol
214 , version ++ "\n"
215 ]
216 in
217 accountKey
218 |> BinaryBase64.decode
219 |> Result.withDefault []
220 |> List.map (Binary.fromDecimal >> Binary.ensureSize 8)
221 |> Binary.concat
222 |> Hmac.encrypt64 SHA.sha256 message
223 |> Binary.chunksOf 8
224 |> List.map Binary.toDecimal
225 |> BinaryBase64.encode