RFC 9425

JSON Meta Application Protocol (JMAP) for Quotas

๐Ÿ“… published June 2023, from ietf

1. Introduction ๐Ÿ’–

Okay bestie, let's get into it! โœจ This is RFC 9425: JSON Meta Application Protocol (JMAP) for Quotas ๐ŸŽ€. It's a Standards Track doc from the IETF, written by R. Cordier, Ed. at Linagora Vietnam, dated June 2023 ๐Ÿฆ‹. The ISSN is 2070-1721. The title block doesn't list anything it obsoletes or updates, so this one is standing on its own ๐Ÿ’….

The whole thing is about one job: giving quota data a clean data model over JMAP, so a client can see the limit on an account and how much of it has been used ๐Ÿ“Š. The abstract says it plainly: this document "specifies a data model for handling quotas on accounts with a server using the JSON Meta Application Protocol (JMAP)" ๐ŸŒธ.

This is an Internet Standards Track document, and it reflects the IETF community's consensus after public review and approval by the IESG ๐Ÿซถ. If you want more on Internet Standards, check Section 2 of RFC 7841. Errata and feedback live at https://www.rfc-editor.org/info/rfc9425.

Copyright is held by the IETF Trust and the document authors, 2023 ๐ŸŒˆ. The doc is subject to BCP 78 and the IETF Trust's Legal Provisions at https://trustee.ietf.org/license-info, so read those before you do anything with it, because they spell out your rights. Code Components pulled out of this doc must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, per the Revised BSD License ๐Ÿ“œ.

1.  Introduction
  1.1.  Notational Conventions
  1.2.  Terminology
2.  Addition to the Capabilities Object
  2.1.  urn:ietf:params:jmap:quota
3.  Sub-types of the Quota Data Type
  3.1.  Scope
  3.2.  ResourceType
4.  Quota
  4.1.  Properties of the Quota Object
  4.2.  Quota/get
  4.3.  Quota/changes
  4.4.  Quota/query
  4.5.  Quota/queryChanges
5.  Examples
  5.1.  Fetching Quotas
  5.2.  Requesting Latest Quota Changes
6.  Push
7.  IANA Considerations
  7.1.  JMAP Capability Registration for "quota"
  7.2.  JMAP Data Type Registration for "Quota"
8.  Security Considerations
9.  Normative References
Acknowledgements
Author's Address

JMAP [RFC8620] is a generic protocol for syncing data like mails, calendars, or contacts between a client and a server ๐Ÿ“ฌ. It's built for mobile and web environments and gives you one consistent interface across different data types โœจ.

This spec defines a data model for quotas over JMAP, so a user can get the details about a given quota ๐Ÿฆ‹. It does not cover quota administration, which should be handled by other means ๐Ÿ™…โ€โ™€๏ธ.

1.1. Notational Conventions

Okay, the key words here are a big deal ๐Ÿ”ฅ. "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they show up in all capitals, exactly like this ๐Ÿ’…. Lowercase ones are just regular words, no cap ๐Ÿ™ˆ.

Type signatures, examples, and property descriptions follow the conventions in Section 1.1 of [RFC8620] ๐ŸŒธ. The data types defined in the core spec get used here too ๐Ÿ’œ.

1.2. Terminology

This doc reuses the terminology from the core JMAP spec, Section 1.6 of [RFC8620] ๐Ÿงš.

The term "Quota" (capitalized) refers to the data type defined in Section 4, and also to an instance of that data type ๐ŸŽ€.

2. Addition to the Capabilities Object ๐ŸŒˆ

The capabilities object comes back as part of the JMAP Session object. See [RFC8620], Section 2 for that ๐Ÿฆ‹.

This document defines one additional capability URI ๐Ÿ’–.

2.1. urn:ietf:params:jmap:quota

This one represents support for the Quota data type and its associated API methods โœจ. Servers supporting this spec MUST add a property called urn:ietf:params:jmap:quota to the capabilities object ๐Ÿซถ. No skipping this one, bestie ๐Ÿ˜ญ.

The value of that property is an empty object. It shows up in both the JMAP Session capabilities property and an account's accountCapabilities property ๐Ÿ“.

3. Sub-types of the Quota Data Type ๐Ÿงš

There are two fields inside the Quota data type that have an enumerated set of possible values. They are:

3.1. Scope

The Scope data type is how we represent the entities a quota applies to ๐ŸŒธ. It's defined as a String with values from this set:

  • account: The quota information applies to just the client's account ๐Ÿ’….
  • domain: The quota information applies to all accounts sharing this domain ๐Ÿก.
  • global: The quota information applies to all accounts belonging to the server ๐ŸŒ.

3.2. ResourceType

The ResourceType data type is the unit of measure for quota usage ๐Ÿ“. It's defined as a String with values from this set:

  • count: The quota is measured in a number of data type objects. For example, a quota can have a limit of 50 "Mail" objects ๐Ÿ“จ.
  • octets: The quota is measured in size, in octets. For example, a quota can have a limit of 25000 octets ๐Ÿ’พ.

4. Quota ๐Ÿ‘‘

The Quota is an object that shows the limit set on an account's usage. It also shows the current usage measured against that limit ๐Ÿ“Š. Iconic.

4.1. Properties of the Quota Object

The Quota object MUST contain the following fields ๐Ÿ’œ:

  • id: Id The unique identifier for this object ๐Ÿ”‘.
  • resourceType: String The resource type of the quota, as defined in Section 3.2 ๐Ÿ“.
  • used: UnsignedInt The current usage of the defined quota, measured in the "resourceType" unit. The server handles the computation of this value ๐Ÿงฎ.
  • hardLimit: UnsignedInt The hard limit set by this quota, measured in the "resourceType" unit. Objects in scope may not be created or updated once this limit is reached ๐Ÿšซ. Hard limit = hard stop, bestie ๐Ÿ’€.
  • scope: String The "Scope" of this quota, as defined in Section 3.1 ๐ŸŒ.
  • name: String The name of the quota. It's useful for managing quotas and for searching with queries ๐Ÿ”.
  • types: String[] A list of all the type names from the "JMAP Types Names" registry (like Email, Calendar, and so on) that this quota applies to. This lets quotas be assigned to distinct or shared data types ๐Ÿงฉ.

The server MUST filter out any types the client didn't request the associated capability for in the "using" section of the request ๐Ÿ›‘. The server MUST NOT return Quota objects that have no types recognized by the client ๐Ÿ™…โ€โ™€๏ธ. Non-negotiable, periodt ๐Ÿ’….

The Quota object MAY contain the following fields ๐ŸŒธ:

  • warnLimit: UnsignedInt|null The warn limit set by this quota, measured in the "resourceType" unit. It's there to send a warning to an entity that's about to hit the hard limit soon, but no action has been taken yet ๐Ÿšจ. If it's set, it SHOULD be lower than the "softLimit" (if present and not null) and the "hardLimit" ๐Ÿ“‰.
  • softLimit: UnsignedInt|null The soft limit set by this quota, measured in the "resourceType" unit. It can still allow some operations while refusing others ๐ŸŽˆ. What's allowed is up to the server. For example, it could block outgoing events of an entity (sending emails, creating calendar events, and so on) while still letting incoming events through (receiving emails, receiving calendar events, and so on) ๐Ÿ“ฌ. If it's set, it SHOULD be higher than the "warnLimit" (if present and not null) but lower than the "hardLimit" ๐Ÿ“ˆ.
  • description: String|null An arbitrary, free, human-readable description of this quota ๐Ÿ“. It might explain where the different limits come from, and which entities and data types the quota applies to ๐Ÿ—‚๏ธ. The description MUST be encoded in UTF-8 [RFC3629], as described in [RFC8620], Section 1.5, and selected based on an Accept-Language header in the request (as defined in [RFC9110], Section 12.5.4), or on out-of-band information about the user's language or locale ๐ŸŒ๐Ÿ’–.

The following JMAP methods are supported ๐Ÿ’….

4.2. Quota/get

This is the standard "/get" method, described in [RFC8620], Section 5.1 ๐ŸŽ€. The _id_'s argument may be "null" to fetch all quotas of the account at once. You'll see that demonstrated in Section 5.1 โœจ.

4.3. Quota/changes

This is the standard "/changes" method, described in [RFC8620], Section 5.2. It has one extra argument in the response ๐Ÿงฉ:

  • updatedProperties: String[]|null If only the "used" Quota property has changed since the old state, this will be a list containing only that property ๐Ÿ”„. If the server can't tell whether only "used" has changed, it MUST be null ๐Ÿซฃ.

"Used" changes all the time, but the other properties usually change only rarely ๐ŸŒธ. So the server can help the client optimize data transfer by tracking quota usage changes separately from other state changes ๐Ÿš€. The updatedProperties array can be used directly through a back-reference in a later Quota/get call in the same request. That way, only these properties come back when nothing else has changed ๐Ÿฆ‹.

Servers MAY decide to add other properties to the list that they judge to be changing frequently ๐Ÿ’ซ.

You can see this method in action in Section 5.2 ๐ŸŽ€.

4.4. Quota/query

This is a standard "/query" method, described in [RFC8620], Section 5.5 ๐Ÿ”.

A FilterCondition object has the following properties. Any of them may be included or left out ๐Ÿ’œ:

  • name: String The Quota _name_ property contains the given string ๐Ÿท๏ธ.
  • scope: String The Quota _scope_ property must match the given value exactly ๐ŸŽฏ.
  • resourceType: String The Quota _resourceType_ property must match the given value exactly ๐Ÿ“.
  • type: String The Quota _types_ property contains the given value ๐Ÿงฉ.

A Quota object matches the FilterCondition if, and only if, all the given conditions match. If zero properties are specified, it's automatically true for all objects ๐ŸŒˆ.

The following Quota properties MUST be supported for sorting ๐Ÿ”ฅ:

  • name
  • used

4.5. Quota/queryChanges

This is a standard "/queryChanges" method, described in [RFC8620], Section 5.6 โœจ.

5.2. Requesting Latest Quota Changes โœจ

Okay bestie, here's how you ask for just the quota changes since your last check ๐Ÿ’… Send a Quota/changes call with the sinceState you already have, then chain a Quota/get onto it using the back-references so you only fetch the quotas that actually changed ๐Ÿฆ‹

Request fetching the changes for a specific quota:

[[ "Quota/changes", {
  "accountId": "u33084183",
  "sinceState": "78540",
  "maxChanges": 20
}, "0" ],
[ "Quota/get", {
  "accountId": "u33084183",
  "#ids": {
    "resultOf": "0",
    "name": "Quota/changes",
    "path": "/updated"
  },
  "#properties": {
    "resultOf": "0",
    "name": "Quota/changes",
    "path": "/updatedProperties"
  }
}, "1" ]]

With response:

[[ "Quota/changes", {
  "accountId": "u33084183",
  "oldState": "78540",
  "newState": "78542",
  "hasMoreChanges": false,
  "updatedProperties": ["used"],
  "created": [],
  "updated": ["2a06df0d-9865-4e74-a92f-74dcc814270e"],
  "destroyed": []
}, "0" ],
[ "Quota/get", {
  "accountId": "u33084183",
  "state": "10826",
  "list": [{
    "id": "2a06df0d-9865-4e74-a92f-74dcc814270e",
    "used": 1246
  }],
  "notFound": []
}, "1" ]]

6. Push ๐Ÿ””

Servers MUST support the JMAP push mechanisms, as specified in [RFC8620], Section 7, so clients can get notified whenever the state changes for the Quota type defined in this spec ๐Ÿซถ


7. IANA Considerations ๐ŸŒธ

7.1. JMAP Capability Registration for "quota" ๐ŸŽ€

IANA has registered the "quota" JMAP Capability like this:

  • Capability Name: urn:ietf:params:jmap:quota
  • Reference: RFC 9425
  • Intended Use: common
  • Change Controller: IETF
  • Security and Privacy Considerations: RFC 9425, Section 8

7.2. JMAP Data Type Registration for "Quota" ๐Ÿงš

IANA has registered the "Quota" Data Type like this:

  • Type Name: Quota
  • Can Reference Blobs: No
  • Can Use for State Change: Yes
  • Capability: urn:ietf:params:jmap:quota
  • Reference: RFC 9425

8. Security Considerations ๐Ÿ”

Okay, this section is serious, so read it carefully ๐Ÿ˜ญ

All security considerations of JMAP [RFC8620] apply to this specification ๐Ÿ’œ

Implementors need to be really careful that the extension in this document doesn't break the site's security policy ๐Ÿ™ˆ The resource usage of other users is probably confidential info, so it should not be divulged to people who aren't authorized to see it.

Here's the tricky part: any resource shared across users (like a quota with the "domain" or "global" scope) means one user who can use that resource can affect what's left for everyone else. For example, a user could spam themselves with events and make the shared resource hit its limit and become unusable for others. Implementors could mitigate that with some rate-limiting on the server ๐Ÿ›ก๏ธ

Also, showing domain and global quota counts to all users can cause privacy leakage of other sensitive data, or at least reveal that the sensitive data exists. For example, some users are part of a private list that belongs to the server, so they shouldn't know how many users are on it. But if you compare the quota count before and after sending a message to that list, you could work out how many people are subscribed, because the domain or global quota count goes up by that number. To limit these attacks, quotas with "domain" or "global" scope SHOULD only be visible to server administrators and not to general users ๐Ÿ‘‘


9. Normative References ๐Ÿ“š


Acknowledgements ๐Ÿ™Œ

Huge thanks to Michael Bailly, who co-wrote the first draft of this doc before deciding to go do other things ๐ŸŒˆ

Thank you to Benoit Tellier for his constant help and support while writing this ๐Ÿ’–

Thank you to Raphael Ouazana for sharing his experience on how to write an RFC after finishing his own document: [RFC9007] โœจ

Thank you to Bron Gondwana, Neil Jenkins, Alexey Melnikov, Joris Baum, and the whole IETF JMAP working group, who had extensive discussions and gave reviews and feedback ๐Ÿฆ‹

Thank you to everyone in the IETF organization who took the time to read, understand, comment, and give great feedback in the last rounds ๐Ÿซถ

Author's Address ๐Ÿ–‹๏ธ

Renรฉ Cordier (editor)
Linagora Vietnam
5 Dien Bien Phu
Hanoi
10000
Vietnam
Email: rcordier@linagora.com
URI:   https://linagora.vn
๐Ÿ“ฆ where this page comes from