github.com/artpar/rclone@v1.67.3/backend/jottacloud/api/types.go (about) 1 // Package api provides types used by the Jottacloud API. 2 package api 3 4 import ( 5 "encoding/xml" 6 "errors" 7 "fmt" 8 "time" 9 ) 10 11 const ( 12 // default time format historically used for all request and responses. 13 // Similar to time.RFC3339, but with an extra '-' in front of 'T', 14 // and no ':' separator in timezone offset. Some newer endpoints have 15 // moved to proper time.RFC3339 conformant format instead. 16 jottaTimeFormat = "2006-01-02-T15:04:05Z0700" 17 ) 18 19 // unmarshalXML turns XML into a Time 20 func unmarshalXMLTime(d *xml.Decoder, start xml.StartElement, timeFormat string) (time.Time, error) { 21 var v string 22 if err := d.DecodeElement(&v, &start); err != nil { 23 return time.Time{}, err 24 } 25 if v == "" { 26 return time.Time{}, nil 27 } 28 newTime, err := time.Parse(timeFormat, v) 29 if err == nil { 30 return newTime, nil 31 } 32 return time.Time{}, err 33 } 34 35 // JottaTime represents time values in the classic API using a custom RFC3339 like format 36 type JottaTime time.Time 37 38 // String returns JottaTime string in Jottacloud classic format 39 func (t JottaTime) String() string { return time.Time(t).Format(jottaTimeFormat) } 40 41 // UnmarshalXML turns XML into a JottaTime 42 func (t *JottaTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 43 tm, err := unmarshalXMLTime(d, start, jottaTimeFormat) 44 *t = JottaTime(tm) 45 return err 46 } 47 48 // MarshalXML turns a JottaTime into XML 49 func (t *JottaTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 50 return e.EncodeElement(t.String(), start) 51 } 52 53 // Rfc3339Time represents time values in the newer APIs using standard RFC3339 format 54 type Rfc3339Time time.Time 55 56 // String returns Rfc3339Time string in Jottacloud RFC3339 format 57 func (t Rfc3339Time) String() string { return time.Time(t).Format(time.RFC3339) } 58 59 // UnmarshalXML turns XML into a Rfc3339Time 60 func (t *Rfc3339Time) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 61 tm, err := unmarshalXMLTime(d, start, time.RFC3339) 62 *t = Rfc3339Time(tm) 63 return err 64 } 65 66 // MarshalXML turns a Rfc3339Time into XML 67 func (t *Rfc3339Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 68 return e.EncodeElement(t.String(), start) 69 } 70 71 // MarshalJSON turns a Rfc3339Time into JSON 72 func (t *Rfc3339Time) MarshalJSON() ([]byte, error) { 73 return []byte(fmt.Sprintf("\"%s\"", t.String())), nil 74 } 75 76 // LoginToken is struct representing the login token generated in the WebUI 77 type LoginToken struct { 78 Username string `json:"username"` 79 Realm string `json:"realm"` 80 WellKnownLink string `json:"well_known_link"` 81 AuthToken string `json:"auth_token"` 82 } 83 84 // WellKnown contains some configuration parameters for setting up endpoints 85 type WellKnown struct { 86 Issuer string `json:"issuer"` 87 AuthorizationEndpoint string `json:"authorization_endpoint"` 88 TokenEndpoint string `json:"token_endpoint"` 89 TokenIntrospectionEndpoint string `json:"token_introspection_endpoint"` 90 UserinfoEndpoint string `json:"userinfo_endpoint"` 91 EndSessionEndpoint string `json:"end_session_endpoint"` 92 JwksURI string `json:"jwks_uri"` 93 CheckSessionIframe string `json:"check_session_iframe"` 94 GrantTypesSupported []string `json:"grant_types_supported"` 95 ResponseTypesSupported []string `json:"response_types_supported"` 96 SubjectTypesSupported []string `json:"subject_types_supported"` 97 IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"` 98 UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported"` 99 RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported"` 100 ResponseNodesSupported []string `json:"response_modes_supported"` 101 RegistrationEndpoint string `json:"registration_endpoint"` 102 TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"` 103 TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported"` 104 ClaimsSupported []string `json:"claims_supported"` 105 ClaimTypesSupported []string `json:"claim_types_supported"` 106 ClaimsParameterSupported bool `json:"claims_parameter_supported"` 107 ScopesSupported []string `json:"scopes_supported"` 108 RequestParameterSupported bool `json:"request_parameter_supported"` 109 RequestURIParameterSupported bool `json:"request_uri_parameter_supported"` 110 CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` 111 TLSClientCertificateBoundAccessTokens bool `json:"tls_client_certificate_bound_access_tokens"` 112 IntrospectionEndpoint string `json:"introspection_endpoint"` 113 } 114 115 // TokenJSON is the struct representing the HTTP response from OAuth2 116 // providers returning a token in JSON form. 117 type TokenJSON struct { 118 AccessToken string `json:"access_token"` 119 ExpiresIn int32 `json:"expires_in"` // at least PayPal returns string, while most return number 120 RefreshExpiresIn int32 `json:"refresh_expires_in"` 121 RefreshToken string `json:"refresh_token"` 122 TokenType string `json:"token_type"` 123 IDToken string `json:"id_token"` 124 NotBeforePolicy int32 `json:"not-before-policy"` 125 SessionState string `json:"session_state"` 126 Scope string `json:"scope"` 127 } 128 129 // JSON structures returned by new API 130 131 // AllocateFileRequest to prepare an upload to Jottacloud 132 type AllocateFileRequest struct { 133 Bytes int64 `json:"bytes"` 134 Created string `json:"created"` 135 Md5 string `json:"md5"` 136 Modified string `json:"modified"` 137 Path string `json:"path"` 138 } 139 140 // AllocateFileResponse for upload requests 141 type AllocateFileResponse struct { 142 Name string `json:"name"` 143 Path string `json:"path"` 144 State string `json:"state"` 145 UploadID string `json:"upload_id"` 146 UploadURL string `json:"upload_url"` 147 Bytes int64 `json:"bytes"` 148 ResumePos int64 `json:"resume_pos"` 149 } 150 151 // UploadResponse after an upload 152 type UploadResponse struct { 153 Path string `json:"path"` 154 ContentID string `json:"content_id"` 155 Bytes int64 `json:"bytes"` 156 Md5 string `json:"md5"` 157 Modified int64 `json:"modified"` 158 } 159 160 // DeviceRegistrationResponse is the response to registering a device 161 type DeviceRegistrationResponse struct { 162 ClientID string `json:"client_id"` 163 ClientSecret string `json:"client_secret"` 164 } 165 166 // CustomerInfo provides general information about the account. Required for finding the correct internal username. 167 type CustomerInfo struct { 168 Username string `json:"username"` 169 Email string `json:"email"` 170 Name string `json:"name"` 171 CountryCode string `json:"country_code"` 172 LanguageCode string `json:"language_code"` 173 CustomerGroupCode string `json:"customer_group_code"` 174 BrandCode string `json:"brand_code"` 175 AccountType string `json:"account_type"` 176 SubscriptionType string `json:"subscription_type"` 177 Usage int64 `json:"usage"` 178 Quota int64 `json:"quota"` 179 BusinessUsage int64 `json:"business_usage"` 180 BusinessQuota int64 `json:"business_quota"` 181 WriteLocked bool `json:"write_locked"` 182 ReadLocked bool `json:"read_locked"` 183 LockedCause interface{} `json:"locked_cause"` 184 WebHash string `json:"web_hash"` 185 AndroidHash string `json:"android_hash"` 186 IOSHash string `json:"ios_hash"` 187 } 188 189 // TrashResponse is returned when emptying the Trash 190 type TrashResponse struct { 191 Folders int64 `json:"folders"` 192 Files int64 `json:"files"` 193 } 194 195 // XML structures returned by the old API 196 197 // Flag is a hacky type for checking if an attribute is present 198 type Flag bool 199 200 // UnmarshalXMLAttr sets Flag to true if the attribute is present 201 func (f *Flag) UnmarshalXMLAttr(attr xml.Attr) error { 202 *f = true 203 return nil 204 } 205 206 // MarshalXMLAttr : Do not use 207 func (f *Flag) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { 208 attr := xml.Attr{ 209 Name: name, 210 Value: "false", 211 } 212 return attr, errors.New("unimplemented") 213 } 214 215 /* 216 GET http://www.jottacloud.com/JFS/<account> 217 218 <user time="2018-07-18-T21:39:10Z" host="dn-132"> 219 <username>12qh1wsht8cssxdtwl15rqh9</username> 220 <account-type>free</account-type> 221 <locked>false</locked> 222 <capacity>5368709120</capacity> 223 <max-devices>-1</max-devices> 224 <max-mobile-devices>-1</max-mobile-devices> 225 <usage>0</usage> 226 <read-locked>false</read-locked> 227 <write-locked>false</write-locked> 228 <quota-write-locked>false</quota-write-locked> 229 <enable-sync>true</enable-sync> 230 <enable-foldershare>true</enable-foldershare> 231 <devices> 232 <device> 233 <name xml:space="preserve">Jotta</name> 234 <display_name xml:space="preserve">Jotta</display_name> 235 <type>JOTTA</type> 236 <sid>5c458d01-9eaf-4f23-8d3c-2486fd9704d8</sid> 237 <size>0</size> 238 <modified>2018-07-15-T22:04:59Z</modified> 239 </device> 240 </devices> 241 </user> 242 */ 243 244 // DriveInfo represents a Jottacloud account 245 type DriveInfo struct { 246 Username string `xml:"username"` 247 AccountType string `xml:"account-type"` 248 Locked bool `xml:"locked"` 249 Capacity int64 `xml:"capacity"` 250 MaxDevices int `xml:"max-devices"` 251 MaxMobileDevices int `xml:"max-mobile-devices"` 252 Usage int64 `xml:"usage"` 253 ReadLocked bool `xml:"read-locked"` 254 WriteLocked bool `xml:"write-locked"` 255 QuotaWriteLocked bool `xml:"quota-write-locked"` 256 EnableSync bool `xml:"enable-sync"` 257 EnableFolderShare bool `xml:"enable-foldershare"` 258 Devices []JottaDevice `xml:"devices>device"` 259 } 260 261 /* 262 GET http://www.jottacloud.com/JFS/<account>/<device> 263 264 <device time="2018-07-23-T20:21:50Z" host="dn-158"> 265 <name xml:space="preserve">Jotta</name> 266 <display_name xml:space="preserve">Jotta</display_name> 267 <type>JOTTA</type> 268 <sid>5c458d01-9eaf-4f23-8d3c-2486fd9704d8</sid> 269 <size>0</size> 270 <modified>2018-07-15-T22:04:59Z</modified> 271 <user>12qh1wsht8cssxdtwl15rqh9</user> 272 <mountPoints> 273 <mountPoint> 274 <name xml:space="preserve">Archive</name> 275 <size>0</size> 276 <modified>2018-07-15-T22:04:59Z</modified> 277 </mountPoint> 278 <mountPoint> 279 <name xml:space="preserve">Shared</name> 280 <size>0</size> 281 <modified></modified> 282 </mountPoint> 283 <mountPoint> 284 <name xml:space="preserve">Sync</name> 285 <size>0</size> 286 <modified></modified> 287 </mountPoint> 288 </mountPoints> 289 <metadata first="" max="" total="3" num_mountpoints="3"/> 290 </device> 291 */ 292 293 // JottaDevice represents a Jottacloud Device 294 type JottaDevice struct { 295 Name string `xml:"name"` 296 DisplayName string `xml:"display_name"` 297 Type string `xml:"type"` 298 Sid string `xml:"sid"` 299 Size int64 `xml:"size"` 300 User string `xml:"user"` 301 MountPoints []JottaMountPoint `xml:"mountPoints>mountPoint"` 302 } 303 304 /* 305 GET http://www.jottacloud.com/JFS/<account>/<device>/<mountpoint> 306 307 <mountPoint time="2018-07-24-T20:35:02Z" host="dn-157"> 308 <name xml:space="preserve">Sync</name> 309 <path xml:space="preserve">/12qh1wsht8cssxdtwl15rqh9/Jotta</path> 310 <abspath xml:space="preserve">/12qh1wsht8cssxdtwl15rqh9/Jotta</abspath> 311 <size>0</size> 312 <modified></modified> 313 <device>Jotta</device> 314 <user>12qh1wsht8cssxdtwl15rqh9</user> 315 <folders> 316 <folder name="test"/> 317 </folders> 318 <metadata first="" max="" total="1" num_folders="1" num_files="0"/> 319 </mountPoint> 320 */ 321 322 // JottaMountPoint represents a Jottacloud mountpoint 323 type JottaMountPoint struct { 324 Name string `xml:"name"` 325 Size int64 `xml:"size"` 326 Device string `xml:"device"` 327 Folders []JottaFolder `xml:"folders>folder"` 328 Files []JottaFile `xml:"files>file"` 329 } 330 331 /* 332 GET http://www.jottacloud.com/JFS/<account>/<device>/<mountpoint>/<folder> 333 334 <folder name="test" time="2018-07-24-T20:41:37Z" host="dn-158"> 335 <path xml:space="preserve">/12qh1wsht8cssxdtwl15rqh9/Jotta/Sync</path> 336 <abspath xml:space="preserve">/12qh1wsht8cssxdtwl15rqh9/Jotta/Sync</abspath> 337 <folders> 338 <folder name="t2"/>c 339 </folders> 340 <files> 341 <file name="block.csv" uuid="f6553cd4-1135-48fe-8e6a-bb9565c50ef2"> 342 <currentRevision> 343 <number>1</number> 344 <state>COMPLETED</state> 345 <created>2018-07-05-T15:08:02Z</created> 346 <modified>2018-07-05-T15:08:02Z</modified> 347 <mime>application/octet-stream</mime> 348 <size>30827730</size> 349 <md5>1e8a7b728ab678048df00075c9507158</md5> 350 <updated>2018-07-24-T20:41:10Z</updated> 351 </currentRevision> 352 </file> 353 </files> 354 <metadata first="" max="" total="2" num_folders="1" num_files="1"/> 355 </folder> 356 */ 357 358 // JottaFolder represents a JottacloudFolder 359 type JottaFolder struct { 360 XMLName xml.Name 361 Name string `xml:"name,attr"` 362 Deleted Flag `xml:"deleted,attr"` 363 Path string `xml:"path"` 364 CreatedAt JottaTime `xml:"created"` 365 ModifiedAt JottaTime `xml:"modified"` 366 Updated JottaTime `xml:"updated"` 367 Folders []JottaFolder `xml:"folders>folder"` 368 Files []JottaFile `xml:"files>file"` 369 } 370 371 /* 372 GET http://www.jottacloud.com/JFS/<account>/<device>/<mountpoint>/.../<file> 373 374 <file name="block.csv" uuid="f6553cd4-1135-48fe-8e6a-bb9565c50ef2"> 375 <currentRevision> 376 <number>1</number> 377 <state>COMPLETED</state> 378 <created>2018-07-05-T15:08:02Z</created> 379 <modified>2018-07-05-T15:08:02Z</modified> 380 <mime>application/octet-stream</mime> 381 <size>30827730</size> 382 <md5>1e8a7b728ab678048df00075c9507158</md5> 383 <updated>2018-07-24-T20:41:10Z</updated> 384 </currentRevision> 385 </file> 386 */ 387 388 // JottaFile represents a Jottacloud file 389 type JottaFile struct { 390 XMLName xml.Name 391 Name string `xml:"name,attr"` 392 Deleted Flag `xml:"deleted,attr"` 393 PublicURI string `xml:"publicURI"` 394 PublicSharePath string `xml:"publicSharePath"` 395 State string `xml:"currentRevision>state"` 396 CreatedAt JottaTime `xml:"currentRevision>created"` 397 ModifiedAt JottaTime `xml:"currentRevision>modified"` 398 UpdatedAt JottaTime `xml:"currentRevision>updated"` 399 Size int64 `xml:"currentRevision>size"` 400 MimeType string `xml:"currentRevision>mime"` 401 MD5 string `xml:"currentRevision>md5"` 402 } 403 404 // Error is a custom Error for wrapping Jottacloud error responses 405 type Error struct { 406 StatusCode int `xml:"code"` 407 Message string `xml:"message"` 408 Reason string `xml:"reason"` 409 Cause string `xml:"cause"` 410 } 411 412 // Error returns a string for the error and satisfies the error interface 413 func (e *Error) Error() string { 414 out := fmt.Sprintf("error %d", e.StatusCode) 415 if e.Message != "" { 416 out += ": " + e.Message 417 } 418 if e.Reason != "" { 419 out += fmt.Sprintf(" (%+v)", e.Reason) 420 } 421 return out 422 }