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  }