idnits 2.17.1 draft-dejong-remotestorage-02.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (10 December 2013) is 3783 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Obsolete informational reference (is this intentional?): RFC 2818 (ref. 'HTTPS') (Obsoleted by RFC 9110) -- Obsolete informational reference (is this intentional?): RFC 2616 (ref. 'HTTP') (Obsoleted by RFC 7230, RFC 7231, RFC 7232, RFC 7233, RFC 7234, RFC 7235) Summary: 0 errors (**), 0 flaws (~~), 1 warning (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 1 INTERNET DRAFT Michiel B. de Jong 2 Document: draft-dejong-remotestorage-02 (independent) 3 F. Kooman 4 Intended Status: Proposed Standard (independent) 5 Expires: 13 June 2014 10 December 2013 7 remoteStorage 9 Abstract 11 This draft describes a protocol by which client-side applications, 12 running inside a web browser, can communicate with a data storage 13 server that is hosted on a different domain name. This way, the 14 provider of a web application need not also play the role of data 15 storage provider. The protocol supports storing, retrieving, and 16 removing individual documents, as well as listing the contents of an 17 individual directory, and access control is based on bearer tokens. 19 Status of this Memo 21 This Internet-Draft is submitted in full conformance with the 22 provisions of BCP 78 and BCP 79. 24 Internet-Drafts are working documents of the Internet Engineering 25 Task Force (IETF). Note that other groups may also distribute 26 working documents as Internet-Drafts. The list of current Internet- 27 Drafts is at http://datatracker.ietf.org/drafts/current/. 29 Internet-Drafts are draft documents valid for a maximum of six months 30 and may be updated, replaced, or obsoleted by other documents at any 31 time. It is inappropriate to use Internet-Drafts as reference 32 material or to cite them other than as "work in progress." 34 This Internet-Draft will expire on 13 June 2014. 36 Copyright Notice 38 Copyright (c) 2013 IETF Trust and the persons identified as the 39 document authors. All rights reserved. 41 This document is subject to BCP 78 and the IETF Trust's Legal 42 Provisions Relating to IETF Documents 43 (http://trustee.ietf.org/license-info) in effect on the date of 44 publication of this document. Please review these documents 45 carefully, as they describe your rights and restrictions with respect 46 to this document. Code Components extracted from this document must 47 include Simplified BSD License text as described in Section 4.e of 48 the Trust Legal Provisions and are provided without warranty as 49 described in the Simplified BSD License. 51 Table of Contents 53 1. Introduction...................................................2 54 2. Terminology....................................................3 55 3. Storage model..................................................3 56 4. Requests.......................................................4 57 5. Response codes.................................................6 58 6. Versioning.....................................................7 59 7. CORS headers...................................................7 60 8. Session description............................................8 61 9. Bearer tokens and access control...............................8 62 10. Application-first bearer token issuance........................9 63 11. Storage-first bearer token issuance...........................10 64 12. Example wire transcripts......................................11 65 12.1. WebFinger................................................11 66 12.2. OAuth dialog form........................................12 67 12.3. OAuth dialog form submission.............................13 68 12.4. OPTIONS preflight........................................13 69 12.5. Initial PUT..............................................14 70 12.6. Subsequent PUT...........................................14 71 12.7. GET......................................................15 72 12.8. DELETE...................................................15 73 13. Distributed versioning........................................16 74 14. Security Considerations.......................................16 75 15. IANA Considerations...........................................18 76 16. Acknowledgments...............................................18 77 17. References....................................................18 78 17.1. Normative References.....................................18 79 17.2. Informative References...................................19 80 18. Authors' addresses............................................20 82 1. Introduction 84 Many services for data storage are available over the internet. This 85 specification describes a vendor-independent interface for such 86 services. It is based on https, CORS and bearer tokens. The 87 metaphor for addressing data on the storage is that of folders 88 containing documents and subfolders. The actions the interface 89 exposes are: 91 * GET a folder: retrieve the names and current versions of the 92 documents and subfolders currently contained by the folder 94 * GET a document: retrieve its content type, current version, 95 and contents 97 * PUT a document: store a new version, its content type, and 98 contents, conditional on the current version 100 * DELETE a document: remove it from the storage, conditional on 101 the current version 103 * HEAD a folder or document: like GET, but omitting the response 104 body 106 The exact details of these four actions are described in this 107 specification. 109 2. Terminology 111 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 112 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 113 document are to be interpreted as described in RFC 2119 [WORDS]. 115 "SHOULD" and "SHOULD NOT" are appropriate when valid exceptions to a 116 general requirement are known to exist or appear to exist, and it is 117 infeasible or impractical to enumerate all of them. However, they 118 should not be interpreted as permitting implementors to fail to 119 implement the general requirement when such failure would result in 120 interoperability failure. 122 3. Storage model 124 The server stores data in nodes that form a tree structure. 125 Internal nodes are called 'folders' and leaf nodes are called 126 'documents'. For a folder, the server stores references to nodes 127 contained in the folder, and it should be able to produce a list of 128 them, with for each contained item: 130 * item name 131 * item type (folder or document) 132 * current version 133 * content type 134 * content length 136 For a document, the server stores, and should be able to produce: 138 * current version 139 * content type 140 * content length 141 * content 143 4. Requests 145 Client-to-server requests SHOULD be made over https [HTTPS], and 146 servers SHOULD comply with HTTP/1.1 [HTTP]. Specifically, they 147 SHOULD support chunked transfer coding on PUT requests. Servers MAY 148 also offer an optional switch from https to SPDY [SPDY]. 150 The root folder of the storage tree is represented by the following 151 URL: 153 URI_ENCODE( '/' ) 155 Subsequently, if is the URL of a folder, then the 156 URL of an item contained in it is: 158 URI_ENCODE( ) 160 for a document, or: 162 URI_ENCODE( '/' ) 164 for a folder. Item names MAY contain all characters except '/' and 165 the null character, and MUST NOT have zero length. 167 A document description is a map containing one string-valued 'ETag' 168 field, one string-valued 'Content-Type' and one integer-valued 169 'Content-Length' field. They represent the document's current 170 version, its content type, and its content length respectively. Note 171 that content length is measured in octets (bytes), not in 172 characters. 174 A folder description is a map containing a string-valued 'ETag' 175 field, representing the folder's current version. 177 A successful GET request to a folder SHOULD be responded to with a 178 JSON-LD [JSON-LD] document (content type 'application/json'), 179 containing as its 'items' field a map in which contained documents 180 appear as entries to a document description, and 181 contained folders appear as entries '/' to a folder 182 description. It SHOULD furthermore contain an '@context' field with 183 the value 'http://remotestorage.io/spec/folder-description'. For 184 instance: 186 { 187 "@context": "http://remotestorage.io/spec/folder-description", 188 "items": { 189 "abc": { 190 "ETag": "DEADBEEFDEADBEEFDEADBEEF", 191 "Content-Type": "image/jpeg", 192 "Content-Length": 82352 193 }, 194 "def/": { 195 "ETag": "1337ABCD1337ABCD1337ABCD" 196 } 197 } 198 } 200 Empty folders are treated as non-existing, and therefore GET 201 requests to them SHOULD be responded to with either a 404 response 202 OR the JSON document representing an empty map ("{}"). However, an 203 empty folder MUST NOT be listed as an item in its parent folder. 205 Also, folders SHOULD be created silently, as necessary to contain 206 newly added items. This way, PUT and DELETE requests only need to be 207 made to documents, and folder management becomes an implicit result. 209 A successful GET request to a document SHOULD be responded to with 210 the full document contents in the body, the document's content type 211 in a 'Content-Type' header, its content length in octets (not in 212 characters) in a 'Content-Length' header, and the document's current 213 version in an 'ETag' header. Content-Range headers on GET requests 214 MAY be supported by the server [HTTP]. 216 A successful PUT request to a document MUST result in: 218 * the request body being stored as the document's new content, 219 * parent and further ancestor folders being silently created as 220 necessary, with the document (name and version) being added to 221 its parent folder, and each folder added to its subsequent 222 parent, 223 * the value of its Content-Type header being stored as the 224 document's new content type, 225 * its version being updated, as well as that of its parent folder 226 and further ancestor folders, using a strong validator [HTTP, 227 section 13.3.3]. 229 The response MUST contain a strong ETag header, with the document's 230 new version (for instance a hash of its contents) as its value. 232 A successful DELETE request to a document MUST result in: 234 * the deletion of that document from the storage, and from its 235 parent folder, 236 * silent deletion of the parent folder if it is left empty by 237 this, and so on for further ancestor folders, 238 * the version of its parent folder being updated, as well as that 239 of further ancestor folders. 241 A successful OPTIONS request SHOULD be responded to as described in 242 the CORS section below. 244 A successful HEAD request SHOULD be responded to like to the 245 equivalent GET request, but omitting the response body. 247 5. Response codes 249 Response codes SHOULD be given as defined by [HTTP, section 10] and 250 [BEARER, section 3.1]. The following is a non-normative checklist 251 of status codes that are likely to occur in practice: 253 * 500 if an internal server error occurs, 254 * 429 if the client makes too frequent requests or is suspected 255 of malicious activity, 256 * 414 if the request URI is too long, 257 * 416 if Range requests are supported by the server and the Range 258 request can not be satisfied, 259 * 401 for all requests that don't have a bearer token with 260 sufficient permissions, 261 * 404 for all DELETE and GET requests to nodes that do not exist 262 on the storage, 263 * 304 for a conditional GET request whose pre-condition 264 fails (see "Versioning" below), 266 * 409 for a PUT request where any folder name in the path 267 clashes with an existing document's name at the same 268 level, or where the document name coincides with an 269 existing folder's name at the same level. 270 * 412 for a conditional PUT or DELETE request whose pre-condition 271 fails (see "Versioning" below), 272 * 507 in case the user's account is over its storage quota, 273 * 4xx for all malformed requests (e.g. foreign characters in the 274 path), as well as for all PUT and DELETE requests to 275 folders, 276 * 2xx for all successful requests. 278 Clients SHOULD also handle the case where a response takes too long 279 to arrive, or where no response is received at all. 281 6. Versioning 283 All successful requests MUST return an 'Expires: 0' header, and an 284 'ETag' header [HTTP] with, in the case of GET, the current version, 285 in the case of PUT, the new version, and in case of DELETE, the 286 version that was deleted. PUT and DELETE requests MAY have an 287 'If-Match' request header [HTTP], and MUST fail with a 412 response 288 code if that doesn't match the document's current version. 290 GET requests MAY have a comma-separated list of revisions in an 291 'If-None-Match' header [HTTP], and SHOULD be responded to with a 412 292 response if that list includes the document or folder's current 293 version. A PUT request MAY have an 'If-None-Match: *' header [HTTP], 294 in which case it MUST fail with a 412 response code if the document 295 already exists. 297 In all 'ETag', 'If-Match' and 'If-None-Match' headers, revision 298 strings should appear inside double quotes ("). 300 A provider MAY offer version rollback functionality to its users, 301 but this specification does not define the user interface for that. 303 7. CORS headers 305 All responses MUST carry CORS headers [CORS]. The server MUST also 306 reply to OPTIONS requests as per CORS. For GET requests, a wildcard 307 origin MAY be returned, but for PUT and DELETE requests, the 308 response MUST echo back the Origin header sent by the client. 310 8. Session description 312 The information that a client needs to receive in order to be able 313 to connect to a server SHOULD reach the client as described in the 314 'bearer token issuance' sections below. It consists of: 316 * , consisting of 'https://' followed by a server 317 host, and optionally a server port and a path prefix as per 318 [IRI]. Examples: 319 * 'https://example.com' (host only) 320 * 'https://example.com:8080' (host and port) 321 * 'https://example.com/path/to/storage' (host, port and 322 path prefix; note there is no trailing slash) 323 * as per [OAUTH]. The token SHOULD be hard to 324 guess and SHOULD NOT be reused from one client to another. It 325 can however be reused in subsequent interactions with the same 326 client, as long as that client is still trusted. Example: 327 * 'ofb24f1ac3973e70j6vts19qr9v2eei' 328 * , always 'draft-dejong-remotestorage-02' for this 329 alternative version of the specification. 331 The client can make its requests using https with CORS and bearer 332 tokens, to the URL that is the concatenation of with 333 '/' plus one or more '/' strings indicating a path in the 334 folder tree, followed by zero or one strings, indicating 335 a document. For example, if is 336 "https://storage.example.com/bob", then to retrieve the folder 337 contents of the /public/documents/ folder, or to retrieve a 338 'draft.txt' document from that folder, the client would make 339 requests to, respectively: 341 * https://storage.example.com/bob/public/documents/ 342 * https://storage.example.com/bob/public/documents/draft.txt 344 9. Bearer tokens and access control 346 A bearer token represents one or more access scopes. These access 347 scopes are represented as strings of the form , 348 where the string SHOULD be lower-case alphanumerical, other 349 than the reserved word 'public', and can be ':r' or ':rw'. 350 The access the bearer token gives is the sum of its access scopes, 351 with each access scope representing the following permissions: 353 '*:rw') any request, 355 '*:r') any GET or HEAD request, 357 ':rw') any requests to paths that start with 358 '/' '/' or '/public/' '/', 360 ':r') any GET or HEAD requests to paths that start with 361 '/' '/' or '/public/' '/', 363 As a special exceptions, GET requests to a document (but not a 364 folder) whose path starts with '/public/' are always allowed. They, 365 as well as OPTIONS requests, can be made without a bearer token. All 366 other requests should present a bearer token with sufficient access 367 scope, using a header of the following form (no double quotes here): 369 Authorization: Bearer 371 In addition, providing the access token via a HTTP query parameter 372 for GET requests MAY be supported by the server, although its use 373 is not recommended, due to its security deficiencies; see [BEARER, 374 section 2.3]. 376 10. Application-first bearer token issuance 378 To make a remoteStorage server available as 'the remoteStorage of 379 at ', exactly one link of the following format SHOULD 380 be added to the webfinger record [WEBFINGER] of at : 382 { 383 "href": , 384 "rel": "remotestorage", 385 "properties": { 386 "http://remotestorage.io/spec/version": , 387 "http://tools.ietf.org/html/rfc6749#section-4.2": , 388 "http://tools.ietf.org/html/rfc6750#section-2.3": , 389 "https://tools.ietf.org/html/rfc2616#section-14.16": 390 } 391 } 393 Here and are as per "Session 394 description" above, and SHOULD be a URL where an 395 OAuth 2.0 implicit-grant flow dialog [OAUTH] is presented, so the 396 user can supply their credentials (how, is out of scope), and allow 397 or reject a request by the connecting application to obtain a bearer 398 token for a certain list of access scopes. 400 The variable SHOULD have the boolean value true if 401 the server supports passing the bearer token in the URI query 402 parameter as per section 2.3 of [BEARER], and false otherwise. 404 The variable SHOULD have a string value of "GET" if 405 Content-Range headers are supported for GET requests as per 406 [HTTP, section 14.16], and the boolean value false if not. 408 The server SHOULD NOT expire bearer tokens unless they are revoked, 409 and MAY require the user to register applications as OAuth clients 410 before first use; if no client registration is required, then the 411 server MAY ignore the client_id parameter in favor of relying on 412 the redirect_uri parameter for client identification. 414 11. Storage-first bearer token issuance 416 The provider MAY also present a dashboard to the user, where they 417 have some way to add open web app manifests [MANIFEST]. Adding a 418 manifest to the dashboard is considered equivalent to clicking 419 'accept' in the dialog of the application-first flow. Removing one 420 is considered equivalent to revoking its access token. 422 As an equivalent to OAuth's 'scope' parameter, a 'remotestorage' 423 field SHOULD be present in the root of such an application manifest 424 document, as a JSON array of strings, each string being one access 425 scope of the form . 427 When the user gestures they want to use a certain application whose 428 manifest is present on the dashboard, the dashboard SHOULD redirect 429 to the application or open it in a new window. To mimic coming back 430 from the OAuth dialog, it MAY add 'access_token' and 'scope' 431 parameters to the URL fragment. 433 Regardless of whether 'access_token' and 'scope' are specified, it 434 SHOULD add a 'remotestorage' parameter to the URL fragment, with a 435 value of the form '@' . When the application detects 436 this parameter, it SHOULD resolve the webfinger record for at 437 and extract the and information. 439 If no access_token was given, then the application SHOULD also 440 extract the information from webfinger, and continue 441 as per application-first bearer token issuance. 443 Note that whereas a remoteStorage server SHOULD offer support of the 444 application-first flow with webfinger and OAuth, it MAY choose not 445 to support the storage-first flow, provided that users will easily 446 remember their '@' webfinger address at that provider. 447 Applications SHOULD, however, support both flows, which means 448 checking the URL for a 'remotestorage' parameter, but giving the 449 user a way to specify their webfinger address if there is none. 451 If a server provides an application manifest dashboard, then it 452 SHOULD merge the list of applications there with the list of 453 issued access tokens as specified by OAuth into one list. Also, 454 the interface for revoking an access token as specified by OAuth 455 SHOULD coincide with removing an application from the dashboard. 457 12. Example wire transcripts 459 The following examples are not normative ("\" indicates a line was 460 wrapped). 462 12.1. WebFinger 464 In application-first, an in-browser application might issue the 465 following request, using XMLHttpRequest and CORS: 467 GET /.well-known/webfinger?resource=acct:michiel@michielbdejon\ 468 g.com HTTP/1.1 469 Host: michielbdejong.com 471 and the server's response might look like this: 473 HTTP/1.1 200 OK 474 Access-Control-Allow-Origin: * 475 Access-Control-Allow-Methods: GET 476 Access-Control-Allow-Headers: If-Match, If-None-Match 477 Access-Control-Expose-Headers: ETag, Content-Type, Content-Len\ 478 gth 480 { 481 "links":[{ 482 "href": "https://michielbdejong.com:7678/inbox", 483 "rel": "post-me-anything" 484 }, { 485 "href": "https://michielbdejong.com/me.jpg", 486 "rel": "avatar" 487 }, { 488 "href": "https://3pp.io:4439/storage/michiel", 489 "rel": "remotestorage", 490 "properties": { 491 "http://remotestorage.io/spec/version": "draft-dejong-re\ 492 motestorage-02", 493 "http://tools.ietf.org/html/rfc6750#section-4.2": "https\ 494 ://3pp.io:4439/oauth/michiel", 495 "http://tools.ietf.org/html/rfc6750#section-2.3": false, 496 "http://tools.ietf.org/html/rfc2616#section-14.16": false 497 } 498 }] 499 } 501 12.2. OAuth dialog form 503 Once the in-browser application has discovered the server's OAuth 504 end-point, it will typically redirect the user to this URL, in 505 order to obtain a bearer token. Say the application is hosted on 506 https://drinks-unhosted.5apps.com/ and wants read-write access to 507 the user's "myfavoritedrinks" scope: 509 GET /oauth/michiel?redirect_uri=https%3A%2F%2Fdrinks-unhosted.5\ 510 apps.com%2F&scope=myfavoritedrinks%3Arw&client_id=https%3A%2F%2Fdrinks-\ 511 unhosted.5apps.com&response_type=token HTTP/1.1 512 Host: 3pp.io 514 The server's response might look like this (truncated for brevity): 516 HTTP/1.1 200 OK 518 519 520 521 Allow access? 522 ... 524 12.3. OAuth dialog form submission 526 When the user submits the form, the request would look something 527 like this: 529 POST /oauth HTTP/1.1 530 Host: 3pp.io:4439 531 Origin: https://3pp.io:4439 532 Content-Type: application/x-www-form-urlencoded 533 Referer: https://3pp.io:4439/oauth/michiel?redirect_uri=https%3\ 534 A%2F%2Fdrinks-unhosted.5apps.com%2F&scope=myfavoritedrinks%3Arw&client_\ 535 id=https%3A%2F%2Fdrinks-unhosted.5apps.com&response_type=token 537 client_id=https%3A%2F%2Fdrinks-unhosted.5apps.com&redirect_uri=\ 538 https%3A%2F%2Fdrinks-unhosted.5apps.com%2F&response_type=token&scope=my\ 539 favoritedrinks%3Arw&state=&username=michiel&password=something&allow=Al\ 540 low 542 To which the server could respond with a 302 redirect, back to the 543 origin of the requesting application: 545 HTTP/1.1 200 OK 546 Location:https://drinks-unhosted.5apps.com/#access_token=j2YnGt\ 547 XjzzzHNjkd1CJxoQubA1o%3D&token_type=bearer&state= 549 12.4. OPTIONS preflight 551 When an in-browser application makes a cross-origin request which 552 may affect the server-state, the browser will make a preflight 553 request first, with the OPTIONS verb, for instance: 555 OPTIONS /storage/michiel/myfavoritedrinks/ HTTP/1.1 556 Host: 3pp.io:4439 557 Access-Control-Request-Method: GET 558 Origin: https://drinks-unhosted.5apps.com 559 Access-Control-Request-Headers: Authorization 560 Referer: https://drinks-unhosted.5apps.com/ 562 To which the server can for instance respond: 564 HTTP/1.1 200 OK 565 Access-Control-Allow-Origin: https://drinks-unhosted.5apps.com 566 Access-Control-Allow-Methods: GET, PUT, DELETE 567 Access-Control-Allow-Headers: Authorization, Content-Length, Co\ 568 ntent-Type, Origin, X-Requested-With, If-Match, If-None-Match 570 12.5. Initial PUT 572 An initial PUT may contain an 'If-None-Match: *' header, like this: 574 PUT /storage/michiel/myfavoritedrinks/test HTTP/1.1 575 Host: 3pp.io:4439 576 Content-Length: 91 577 Origin: https://drinks-unhosted.5apps.com 578 Authorization: Bearer j2YnGtXjzzzHNjkd1CJxoQubA1o= 579 Content-Type: application/json; charset=UTF-8 580 Referer: https://drinks-unhosted.5apps.com/? 581 If-None-Match: * 583 {"name":"test","@context":"http://remotestorage.io/spec/modules\ 584 /myfavoritedrinks/drink"} 586 And the server may respond with either a 201 Created or a 200 OK 587 status: 589 HTTP/1.1 201 Created 590 Access-Control-Allow-Origin: https://drinks-unhosted.5apps.com 591 ETag: "1382694045000" 593 12.6. Subsequent PUT 595 A subsequent PUT may contain an 'If-Match' header referring to the 596 ETag previously returned, like this: 598 PUT /storage/michiel/myfavoritedrinks/test HTTP/1.1 599 Host: 3pp.io:4439 600 Content-Length: 91 601 Origin: https://drinks-unhosted.5apps.com 602 Authorization: Bearer j2YnGtXjzzzHNjkd1CJxoQubA1o= 603 Content-Type: application/json; charset=UTF-8 604 Referer: https://drinks-unhosted.5apps.com/? 605 If-Match: "1382694045000" 607 {"name":"test", "updated":true, "@context":"http://remotestorag\ 608 e.io/spec/modules/myfavoritedrinks/drink"} 609 And the server may respond with a 412 Conflict or a 200 OK status: 611 HTTP/1.1 200 OK 612 Access-Control-Allow-Origin: https://drinks-unhosted.5apps.com 613 ETag: "1382694048000" 615 12.7. GET 617 A GET request would also include the bearer token, and optionally 618 an If-None-Match header: 620 GET /storage/michiel/myfavoritedrinks/test HTTP/1.1 621 Host: 3pp.io:4439 622 Origin: https://drinks-unhosted.5apps.com 623 Authorization: Bearer j2YnGtXjzzzHNjkd1CJxoQubA1o= 624 Referer: https://drinks-unhosted.5apps.com/? 625 If-None-Match: "1382694045000", "1382694048000" 627 {"name":"test", "updated":true, "@context":"http://remotestora\ 628 ge.io/spec/modules/myfavoritedrinks/drink"} 630 And the server may respond with a 304 Not Modified or a 200 OK 631 status: 633 HTTP/1.1 304 Not Modified 634 Access-Control-Allow-Origin: https://drinks-unhosted.5apps.com 635 ETag: "1382694048000" 637 12.8. DELETE 639 A DELETE request may look like this: 641 DELETE /storage/michiel/myfavoritedrinks/test HTTP/1.1 642 Host: 3pp.io:4439 643 Origin: https://drinks-unhosted.5apps.com 644 Authorization: Bearer j2YnGtXjzzzHNjkd1CJxoQubA1o= 645 Content-Type: application/json; charset=UTF-8 646 Referer: https://drinks-unhosted.5apps.com/? 647 If-Match: "1382694045000" 649 And the server may respond with a 412 Conflict or a 200 OK status: 651 HTTP/1.1 412 Conflict 652 Access-Control-Allow-Origin: https://drinks-unhosted.5apps.com 653 ETag: "1382694048000" 655 13. Distributed versioning 657 This section is non-normative, and is intended to explain some of 658 the design choices concerning ETags and folder listings. At the 659 same time it will hopefully help readers who intend to develop an 660 application that uses remoteStorage as its per-user data storage. 661 When multiple clients have read/write access to the same document, 662 versioning conflicts may occur. For instance, client A may make 663 a PUT request that changes the document from version 1 to version 664 2, after which client B may make a PUT request attempting to change 665 the same document from version 1 to version 3. 667 In this case, client B can add an 'If-Match: "1"' header, which 668 would trigger a 412 Conflict response code, since the current 669 version ("2") does not match the version required as a condition by 670 the header If-Match header ("1"). 672 Client B is now aware of the conflict, and may consult the user, 673 saying the update to version 3 failed. The user may then choose, 674 through the user interface of client B, whether version 2 or 675 version 3 should be kept, or maybe the document should be reverted 676 on the server to version 1, or a merged version 4 is needed. Client 677 B may then make a request that puts the document to the version the 678 user wishes; this time setting an 'If-Match: "2"' header instead. 680 Both client A and client B would periodically poll the root 681 directory of each scope they have access to, to see if the version 682 of the root directory changed. If it did, then one of the versions 683 listed in there will necessarily have changed, and the client can 684 make a GET request to that child directory or document, to obtain 685 its latest version. 687 Because an update in a document will result in a version change of 688 its containing folder, and that change will propagate all the way 689 to the root folder, it is not necessary to poll each document for 690 changes individually. 692 As an example, the root folder may contain 10 directories, 693 each of which contain 10 directories, which each contain 10 694 documents, so their paths would be for instance '/0/0/1', '/0/0/2', 695 etcetera. Then one GET request to the root folder '/' will be 696 enough to know if any of these 1000 documents has changed. 698 Say document '/7/9/2' has changed; then the GET request to '/' will 699 come back with a different ETag, and entry '7/' will have a 700 different value in its JSON content. The client could then request 701 '/7/', '/7/9/', and '/7/9/2' to narrow down the one document that 702 caused the root directory's ETag to change. 704 Note that the remoteStorage server does not get involved in the 705 conflict resolution. It keeps the canonical current version at all 706 times, and allows clients to make conditional GET and PUT requests, 707 but it is up to whichever client discovers a given version 708 conflict, to resolve it. 710 14. Security Considerations 712 To prevent man-in-the-middle attacks, the use of https instead of 713 http is important for both the interface itself and all end-points 714 involved in webfinger, OAuth, and (if present) the storage-first 715 application launch dashboard. 717 A malicious party could link to an application, but specifying a 718 remoteStorage user address that it controls, thus tricking the user 719 into using a trusted application to send sensitive data to the wrong 720 remoteStorage server. To mitigate this, applications SHOULD clearly 721 display to which remoteStorage server they are sending the user's 722 data. 724 Applications could request scopes that the user did not intend to 725 give access to. The user SHOULD always be prompted to carefully 726 review which scopes an application is requesting. 728 An application may upload malicious html pages and then trick the 729 user into visiting them, or upload malicious client-side scripts, 730 that take advantage of being hosted on the user's domain name. The 731 origin on which the remoteStorage server has its interface SHOULD 732 therefore NOT be used for anything else, and the user SHOULD be 733 warned not to visit any web pages on that origin. In particular, the 734 OAuth dialog and launch dashboard or token revokation interface 735 SHOULD be on a different origin than the remoteStorage interface. 737 Where the use of bearer tokens is impractical, a user may choose to 738 store documents on hard-to-guess URLs whose path after 739 starts with '/public/', while sharing this URL only 740 with the intended audience. That way, only parties who know the 741 document's hard-to-guess URL, can access it. The server SHOULD 742 therefore make an effort to detect and stop brute-force attacks that 743 attempt to guess the location of such documents. 745 The server SHOULD also detect and stop denial-of-service attacks 746 that aim to overwhelm its interface with too much traffic. 748 15. IANA Considerations 750 This document registers the 'remotestorage' link relation, as well 751 as the following WebFinger properties: 752 * "http://remotestorage.io/spec/version" 753 * "http://tools.ietf.org/html/rfc6749#section-4.2" 754 * "http://tools.ietf.org/html/rfc6750#section-2.3" 755 * "https://tools.ietf.org/html/rfc2616#section-14.16 757 16. Acknowledgements 759 The authors would like to thank everybody who contributed to the 760 development of this protocol, including Kenny Bentley, Javier Diaz, 761 Daniel Groeber, Bjarni Runar, Jan Wildeboer, Charles Schultz, Peter 762 Svensson, Valer Mischenko, Michiel Leenaars, Jan-Christoph 763 Borchardt, Garret Alfert, Sebastian Kippe, Max Wiehle, Melvin 764 Carvalho, Martin Stadler, Geoffroy Couprie, Niklas Cathor, Marco 765 Stahl, James Coglan, Ken Eucker, Daniel Brolund, elf Pavlik, Nick 766 Jennings, Markus Sabadello, Steven te Brinke, Matthias Treydte, 767 Rick van Rein, Mark Nottingham, Julian Reschke, and Markus 768 Lanthaler, among many others. 770 17. References 772 17.1. Normative References 774 [WORDS] 775 Bradner, S., "Key words for use in RFCs to Indicate Requirement 776 Levels", BCP 14, RFC 2119, March 1997. 778 [IRI] 779 Duerst, M., "Internationalized Resource Identifiers (IRIs)", 780 RFC 3987, January 2005. 782 [WEBFINGER] 783 Jones, P., Salguerio, G., Jones, M, and Smarr, J., 784 "WebFinger", RFC7033, September 2013. 786 [OAUTH] 787 "Section 4.2: Implicit Grant", in: Hardt, D. (ed), "The OAuth 788 2.0 Authorization Framework", RFC6749, October 2012. 790 17.2. Informative References 792 [HTTPS] 793 Rescorla, E., "HTTP Over TLS", RFC2818, May 2000. 794 [HTTP] 795 Fielding et al., "Hypertext Transfer Protocol -- HTTP/1.1", 796 RFC2616, June 1999. 798 [SPDY] 799 Mark Belshe, Roberto Peon, "SPDY Protocol - Draft 3.1", http:// 800 www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1, 801 September 2013. 803 [JSON-LD] 804 M. Sporny, G. Kellogg, M. Lanthaler, "JSON-LD 1.0", W3C 805 Proposed Recommendation, 806 http://www.w3.org/TR/2013/PR-json-ld-20131105/, November 2013. 808 [CORS] 809 van Kesteren, Anne (ed), "Cross-Origin Resource Sharing -- 810 W3C Candidate Recommendation 29 January 2013", 811 http://www.w3.org/TR/cors/, January 2013. 813 [MANIFEST] 814 Mozilla Developer Network (ed), "App manifest -- Revision 815 330541", https://developer.mozilla.org/en- 816 US/Apps/Developing/Manifest$revision/482369, October 2013. 818 [BEARER] 819 M. Jones, D. Hardt, "The OAuth 2.0 Authorization Framework: 820 Bearer Token Usage", RFC6750, 821 http://tools.ietf.org/html/rfc6750#section-2.3, October 2012. 823 18. Authors' addresses 825 Michiel B. de Jong 826 (independent) 828 Email: michiel@michielbdejong.com 830 F. Kooman 831 (independent) 833 Email: fkooman@tuxed.net