-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
capnpstrs.gen.go
33 lines (31 loc) · 290 KB
/
capnpstrs.gen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main
// This file was auto-generated by ./internal/gen-schema-strings.go.
// DO NOT EDIT.
var CapnpFileMap = map[string]string{
"api-session.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xeb014c0c3413cbfb;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing WebSession = import \"web-session.capnp\";\nusing IpAddress = import \"ip.capnp\".IpAddress;\n\ninterface ApiSession @0xc879e379c625cdc7 extends(WebSession.WebSession) {\n # A special case of WebSession but for APIs. It doesn't provide much other\n # than a unique type id that we can identify ApiSessions with\n\n struct Params {\n # Normally, we strip the remote address from requests, since most applications shouldn't need\n # it. However, for those that benefit from it (like analytics), clients can opt into passing\n # their IP on to the backend by adding an \"X-Sandstorm-Passthrough: address\" header to their\n # request. This would be a privacy leak for WebSession, since the grain can give the client\n # scripts which would send the header, but ApiSession requires a user action, so it's safe\n # here.\n remoteAddress @0 :IpAddress;\n }\n\n struct PowerboxTag {\n # A tag used for PowerboxDescriptors describing HTTP APIs. Such descriptors should typically\n # indicate `ApiSession` as the requested interface and use PowerboxTag to specify what API is\n # expected (so, the tag ID is ApiSession's ID, but the tag value is an ApiSession.PowerboxTag).\n #\n # Usually, this tag is used to request APIs implemented by internet services external to\n # Sandstorm. However, a Sandstorm grain may advertise itself as supporting a compatible API\n # to the Powerbox, and if so the Powerbox will allow the user to select that grain for such\n # requests. Note that publishing an `ApiSession` has nothing to do with `UiView` or Sandstorm's\n # normal HTTP API support.\n #\n # Requests of this type trigger the HTTP driver, such that the powerbox UI will display a\n # special flow for connecting to external web services. The Powerbox will also surface other\n # grains that advertise their ability to handle these requests under the usual matching rules.\n # This struct is carefully designed such that the usual Powerbox query rules make sense for\n # performing such queries.\n #\n # If you make a Powerbox request containing multiple PowerboxDescriptors describing HTTP APIs,\n # the HTTP driver will offer the user a choice among the options. This can make sense for, say,\n # allowing the user to choose from multiple popular servers implementing the same protocol, or\n # to choose whether or not to grant the app optional permissions (OAuth scopes). The HTTP\n # driver will return a capability with a descriptor matching one of the requested descriptors\n # which best-describes the user's choice.\n\n canonicalUrl @0 :Text;\n # The standard URL at which this service is found. Use this especially for traditional SaaS\n # services. For example, you might request \"https://api.github.com\" to request access to the\n # GitHub API.\n #\n # If you include a path in the URL, requests will automatically be prefixed with that path. You\n # should usually include enough path components to identify a specific product and version, but\n # usually not specific collection types within that product. For example, you would request the\n # Google Calendar API version 2 as \"https://apidata.googleusercontent.com/caldav/v2\". However,\n # you would not normally request \"https://api.github.com/users\" because \"GitHub users\" is not\n # considered a separate API but rather one part of the overall GitHub API. Note that\n # `canonicalUrl` should never end with a '/', because a '/' is added implicitly to separate\n # the API URL from the individual request's path.\n #\n # The HTTP driver will present `canonicalUrl` as a strong suggestion to the user. However, the\n # user is always allowed to substitute a different URL instead, causing requests to be\n # redirected to some other service. This is the user's choice. In cases where the app does not\n # trust the user, the app will need to defend itself against the possibility that the user\n # connects it to a malicious server.\n #\n # The Powerbox will also offer matches published by other grains using the usual query matching\n # rules. That is, a grain may advertise that it can handle queries for HTTP APIs with a\n # particular `canonicalUrl`, indicating that the grain offers ApiSession capabilities\n # implementing a compatible protocol.\n #\n # TODO(soon): How do we request a standard protocol that doesn't have a canonical URL, like\n # WebDAV? Does any of ApiSession.PowerboxTag even make sense in this case?\n # TODO(soon): How do we request a single resource with a particular MIME type? Probably should\n # be a separate interface, which http-bridge can implement...\n\n struct OAuthScope {\n name @0 :Text;\n }\n\n oauthScopes @1 :List(OAuthScope);\n # List of OAuth scopes required by the requesting app. OAuth APIs usually publish a list\n # of \"scope\" names representing permissions that can be requested. For example, see:\n #\n # https://developer.github.com/v3/oauth/#scopes\n #\n # When this list is present (even if empty), it indicates that the requested API requires\n # OAuth-based authentication. The HTTP driver will guide the user through connecting their\n # Sandstorm account to the remote service and requesting the appropriate permissions.\n #\n # The Sandstorm project maintains an ad hoc mapping of hostnames to OAuth endpoints allowing\n # the HTTP driver to automatically determine what kind of OAuth request to make for a given\n # `canonicalUrl`. For example, if `canonicalUrl` is `https://api.github.com`, the HTTP driver\n # will initiate a Github OAuth handshake. For any URL under apidata.googleusercontent.com, the\n # driver will initiate a Google OAuth handshake. Etc. Unfortunately, it is not possible to\n # make OAuth requests to endpoints not on the list. However, we welcome pull requests to add\n # new endpoints, large or small.\n #\n # Sandstorm grains offering compatible APIs may wish to list the OAuth scopes they support.\n # Powerbox matching rules state that when a Powerbox query and potential matching descriptor\n # both contain a field of list-of-struct type, then they are treated as sets, and the match\n # must advertise a superset of the request. Therefore, if you list OAuth scopes when\n # publishing, then only requests for a subset of these will lead to your offer being listed in\n # the Powerbox. Often, offers will want to leave `oauthScopes` null, which will cause the scope\n # list to be ignored for matching purposes (always match).\n\n authentication @2 :Text;\n # If not null, indicates that this endpoint is expected to need old-fashion authentication.\n # The field contains a text string naming the type of authentication. Currently there is only\n # one type recognized: \"basic\", meaning HTTP Basic Auth. Specifying this instructs the HTTP\n # driver to prompt the user for a username and password.\n #\n # Note that even if this isn't specified, the HTTP driver will probe the target server to see\n # if it demands authentication and, if so, will prompt the user for a password anyway. Thus\n # this is only needed in cases where the target server supports both authenticated and\n # unauthenticated use and thus the probe will not notice the need for authentication.\n #\n # When publishing support of HTTP APIs to the Powerbox, you should usually leave this field\n # null, so that it is not considered for matching.\n }\n}\n",
"appid-replacements.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xa53cae3f717a1676;\n# This file is used to recover from lost or stolen app keys.\n#\n# If you are an app developer and you have lost access to your key or suspect it may have been\n# compromised, do the following:\n# 1. Generate a new key using `vagrant-spk keygen`. The new key ID will be printed.\n# 2. Use `vagrant-spk getkey <key-id> > backup.key` to make a backup copy of the key. Put\n# `backup.key` somewhere safe! Of course, do NOT make this file public!\n# 3. Add an entry to `appIdReplacementList` below with `original` being your old key ID (app ID)\n# and `replacement` being the new key ID (as printed when you generated it).\n# 4. PGP-sign your git commit using the `-S` flag, using the same PGP key you used to sign older\n# versions of your app as published to the app market. (If you can't do this, we'll need to\n# verify your identity in some other way.)\n# 5. Submit a pull request.\n#\n# Things you should NOT do:\n# * Do NOT change sandstorm-pkgdef.capnp to the new key. Once Sandstorm is updated with your PR,\n# the spk tool will automatically use the new key where appropriate.\n# * Do NOT update your `pgpSignature` file. The signature should still assert ownership of the\n# original app ID.\n# * Do NOT update links to the app market or anywhere else that incorporate the app ID. Your app ID\n# is not changing; only the signing key is changing.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm::spk\");\n\nstruct AppIdReplacement {\n # Specifies that packages signed by the app ID specified in `replacement` shall henceforth be\n # treated as if they had instead be signed by `original`. Hence, packages signed with the\n # replacement key will be accepted as upgrades to the original and will be displayed as if\n # they had the original ID.\n\n original @0 :Text;\n # The original App ID, in text format for convenience. This is the canonical ID for this app,\n # and will remain so going forward.\n\n replacement @1 :Text;\n # The replacement App ID, in text format for convenience. Packages signed with this ID will be\n # treated as if they are signed with the original ID. Omit this to revoke an ID with no\n # replacement.\n #\n # Note: Do NOT distribute any packages signed with the new ID until a Sandstorm release has gone\n # out with your app ID replacement, otherwise people who install the app too early will be unable\n # to update it.\n\n revokeExceptPackageIds @2 :List(Text);\n # A list of package IDs (in text format for convenience) which were signed with the original\n # key and are known to be authentic versions of this app. All other packages signed with the\n # original key will be presumed malicious and rejected.\n #\n # Only specify this if the original key may have been compromised. If the key was merely lost\n # (e.g. storage was destroyed with no backup) then there is no need to revoke the old key.\n # In this case, omit this field (making it null).\n}\n\nconst appIdReplacementList :List(AppIdReplacement) = [\n # ---- example entry ----\n\n (original = \"vjvekechd398fn1t1kn1dgdnmaekqq9jkjv3zsgzymc4z913ref0\",\n replacement = \"wq95qmutckc0yfmecv0ky96cqxgp156up8sv81yxvmery58q87jh\",\n revokeExceptPackageIds = [\"b5bb9d8014a0f9b1d61e21e796d78dcc\"]),\n # This is the ID for My Cool Example App by Kenton Varda. The old app key was compromised when\n # it was accidentally committed to the app's public git repo. Only one version (\"b5bb...\") had\n # ever been published.\n\n # ---- end example; real entries follow ----\n\n # ---- Paperwork entry ----\n\n (original = \"vxe8awcxvtj6yu0vgjpm1tsaeu7x8v8tfp71tyvnm6ykkephu9q0\",\n replacement = \"n8cn71407n4mezn7mg0k5kkm21juuphhecc24hdf9kf56zyxm4ah\"),\n # This is the ID for the Paperwork app by JJ. The old app key was destroyed\n\n # ---- end Paperwork entry ----\n\n # ---- draw.io entry ----\n\n (original = \"nfqhx83vvzm80edpgkpax8mhqp176qj2vwg67rgq5e3kjc5r4cyh\",\n replacement = \"a3w50h1435gsxczugm16q0amwkqm9f4crykzea53sv61pt7phk8h\",\n revokeExceptPackageIds = [\n \"1450e0caa29b59ec938b3795bf17cb02\", \"738f0e56a9ca462e77245e3f392686d7\"]),\n # This is the ID for draw.io. The old app key may have been leaked (probably not, but we're\n # cautious). Two versions had been published under the original key.\n\n # ---- end draw.io entry ----\n\n # ---- Wekan entry ----\n\n (original = \"m86q05rdvj14yvn78ghaxynqz7u2svw6rnttptxx49g1785cdv1h\",\n replacement = \"6jz1aawur7kga7tdsj9kgpxx1yzh6xz1qmrpnqukcp1rekprd9f0\"),\n # The original key is held by Maxime Quandalle. The Sandstorm team generated this replacement\n # key in order to publish the update posted [here](https://github.com/wekan/wekan/pull/704),\n # after failing to contact Maxime over the course of many weeks.\n #\n # See also [this discussion](https://github.com/wekan/wekan/issues/640) about the future\n # governance of Wekan.\n\n# ---- end Wekan entry ----\n\n # Add your entry here!\n];\n",
"payments.capnp": "# Sandstorm Blackrock\n# Copyright (c) 2016 Sandstorm Development Group, Inc.\n# All Rights Reserved\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xd512486208994241;\n\n$import \"/capnp/c++.capnp\".namespace(\"blackrock\");\n\nusing import \"util.capnp\".LocalizedText;\nusing import \"supervisor.capnp\".SystemPersistent;\n\ninterface PaymentSource {\n # A payment source, like a credit card. Powerbox-request one of these in order to prompt the\n # user to choose a payment source or add a new one.\n\n getTitle @0 () -> (title :LocalizedText);\n # Probably something like: \"VISA ***4242\"\n}\n\ninterface PaymentAcceptor {\n # Used to charge money from the user's credit card.\n #\n # Powerbox-request this capability in order to accept payments.\n #\n # The server admin on Blackrock can obtain a PaymentAcceptor that makes payments to the server's\n # bank account -- the same place where hosting subscription payments go.\n\n createPayment @0 (source :PaymentSource, invoice :Invoice)\n -> CreatePaymentResults;\n # Initiate a payment. If this completes successfully, the payment is authorized but has not yet\n # been committed. The app should commit the payment as soon as it is able to do so safely.\n # If not committed, the payment will eventually expire with no money being moved.\n #\n # In order to avoid double-payments, payments must use two-phase commit:\n # 1. Call createPayment() to authorize the payment. The payment is not actually paid yet.\n # 2. `save()` the returned Payment.\n # 3. Write a journal entry about the payment and the effect it should have once it completes, in\n # such a way that applying said effect is idempotent. Make sure this entry is flushed to disk,\n # such that if a failure occurs, the journal will be replayed later.\n # 4. Call payment.commit().\n # 5. Apply the changes which the payment is supposed to effect, flushing all changes to disk.\n # 6. Delete the journal entry or mark it committed, so that it doesn't replay.\n\n struct CreatePaymentResults {\n union {\n success :group {\n # Payment was authorized.\n payment @0 :Payment;\n }\n\n failed :group {\n # Payment was declined.\n description @1 :LocalizedText;\n }\n }\n }\n\n struct Invoice {\n items @0 :List(Item);\n struct Item {\n title @0 :LocalizedText;\n amountCents @1 :Int32;\n }\n }\n}\n\ninterface Payment {\n # An authorized payment.\n\n commit @0 ();\n # Completes the payment, if it hasn't completed already. Returns successfully if the payment\n # succeeded (either as a result of this call or a previosu call). This call is idempotent.\n}\n\ninterface PersistentPaymentSource extends(PaymentSource, SystemPersistent) {}\ninterface PersistentPaymentAcceptor extends(PaymentAcceptor, SystemPersistent) {}\ninterface PersistentPayment extends(Payment, SystemPersistent) {}\n",
"web-publishing.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xd5d3e63bd0a552b6;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing Handle = Util.Handle;\n\ninterface WebSite @0xdddcca47803e2377 {\n # Represents an HTTP URL to which a web site can be published.\n #\n # Make a powerbox request for `WebSite` when you wish to publish a web site accessible over HTTP\n # without going through the Sandstorm UI.\n\n getUrl @0 () -> (path :Text);\n # Get the URL of this resource.\n\n struct Entity {\n # An HTTP entity (using the term \"entity\" as defined in the HTTP spec). Think of this as the\n # \"payload\" of an HTTP response.\n\n mimeType @0 :Text; # Content-Type header.\n language @1 :Text; # Content-Language header (optional).\n encoding @2 :Text; # Content-Encoding header (optional).\n\n body :union {\n bytes @3 :Data;\n # Use when content is smaller than 1MB.\n\n blob @4 :Util.Blob;\n # Use when content is larger than 1MB. Currently, the blob must be created via uploadBlob().\n }\n\n redirectTo @5 :Text;\n # If non-null, this entity is a 301 redirect to the URL `redirectTo`, which may be relative or\n # absolute.\n #\n # The redirect is always a 301 redirect. Other redirect types do not make much sense in the\n # context of a static web site. Note that the web publishing driver will set cache control\n # headers on these responses just like any other, so a 301 redirect isn't really \"permanent\".\n }\n\n getEntities @1 (path :Text) -> (entities :Util.Assignable(List(Entity)));\n # Get the list of static HTTP entities that make up the resource at the given path. Often there\n # is only one entity, but if you provide multiple entities, one will be chosen based on \"Accept\"\n # headers provided by the client. Setting the entity list empty effectively deletes the resource;\n # the client will receive a 404 error, which can be customized using `getNotFoundEntities()`.\n #\n # The path normally should not contain the character '?' nor '#'; if it does, then requests for\n # this resource will have to URL-escape those characters since otherwise they have special\n # meanings.\n #\n # The path normally should not include a leading '/'; getUrl() normally returns a string with\n # a trailing '/', and `path` should only contain text intended to be appended to that.\n\n listResources @5 (shallow :Bool) -> (names :List(Text));\n # Enumerate the names of all resources which have non-empty entity lists. If `shallow` is true,\n # then names will be truncated after the first '/' and de-duped to simulate a directory structure\n # (even though web sites aren't necessarily stored this way). Note that if a resource is mapped\n # at the site root (which usually there is!) then the returned list will include an empty string.\n\n getNotFoundEntities @2 () -> (entities :Util.Assignable(List(Entity)));\n # Get the entity set used to respond when a path is not found. Such responses also have HTTP\n # error code 404.\n\n uploadBlob @3 () -> (blob :Util.Blob, stream :Util.ByteStream);\n # Upload a data blob to be stored by the driver and possibly used as an entity-body.\n #\n # The content of the blob must be written to the returned stream. Once `done()` is called on the\n # stream, the blob is ready. Before that point, calling methods on the blob may block waiting\n # until enough data has actually been uploaded for them to respond. If the stream is dropped\n # without calling `done()`, the blob will be left in a broken state in which some methods will\n # throw exceptions.\n\n getSubsite @4 (prefix :Text) -> (site :WebSite);\n # Append `prefix` to the URL and return a `WebSite` capability that can only modify resources\n # under that URL. Note that the web driver assigns *no* special meaning to the character '/', so\n # you should use a suffix ending in '/' if you want a site that represents a subdirectory.\n\n # TODO(someday): Allow registering dynamic handlers.\n\n # TODO(someday): Allow transactionally changing a bunch of things at once.\n}\n",
"appid-replacements-test.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xbee445adfb01a777;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\nusing AppIdReplacement = import \"appid-replacements.capnp\".AppIdReplacement;\n\nstruct TestIds { # namespace only\n const unusedApp :Text = \"6pm4ujs8f5f5wugc87uhuhvhs57he09u10rv8qd2jgdup9f69yzh\";\n\n const app1 :Text = \"vjvekechd398fn1t1kn1dgdnmaekqq9jkjv3zsgzymc4z913ref0\";\n const app2 :Text = \"wq95qmutckc0yfmecv0ky96cqxgp156up8sv81yxvmery58q87jh\";\n const app3 :Text = \"302t6c6kf8hjer1kh3469d4ch10d936g7wkwtxcs12pwh9u5axqh\";\n const app4 :Text = \"5ddk4uqnstnsqvp3thc2tyed41c7wp4x5ygt20zrh3u0tnv5jqd0\";\n const app5 :Text = \"jkz6yhywhp4uk5sgkc5ugwnee57a5h5wu4rfmujtahny5r8g3ych\";\n const app6 :Text = \"adk6syfj42fpp3xhgqrrheqgfxkhaw8e1t11vug44ys6pzaxqugh\";\n\n const unusedPkg :Text = \"7300e3448dd2b53e075d0a8481c2bc06\";\n\n const pkg1 :Text = \"b5bb9d8014a0f9b1d61e21e796d78dcc\";\n const pkg2 :Text = \"8613a11b8ac365cb36775a6b8ca6176c\";\n const pkg3 :Text = \"77c4f45aee83e376d31a5680cdb841a2\";\n}\n\nconst testAppIdReplacementList :List(AppIdReplacement) = [\n (original = TestIds.app1, replacement = TestIds.app2,\n revokeExceptPackageIds = [TestIds.pkg1, TestIds.pkg2]),\n\n (original = TestIds.app2, replacement = TestIds.app3),\n\n (original = TestIds.app4, replacement = TestIds.app5),\n\n (original = TestIds.app5, replacement = TestIds.app6,\n revokeExceptPackageIds = [TestIds.pkg3]),\n];\n",
"email.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This is used specifically with hack-session.capnp.\n# It is subject to change after the Powerbox functionality is implemented.\n\n@0xdd10df585a82c6d8;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Grain = import \"grain.capnp\";\nusing Util = import \"util.capnp\";\n\nstruct EmailAddress {\n # Email addresses are (usually) of the form \"Full Name <[email protected]>\".\n # This struct separates the display name and address into distinct fields.\n\n address @0 :Text;\n name @1 :Text;\n\n # TODO(someday): We could add a field `token` which is a capability representing \"email capital\",\n # which you can think of like \"political capital\", but specifically representing some social\n # permission to send email to this address. A token can be used some small number of times to\n # send email to a particular address. Tokens can be requested using the inline powerbox: if a\n # human user types (or selects from autocomplete) an address, this is good enough to allow the\n # app to send a few messages to that address. Tokens would also be received as part of incoming\n # messages, representing permission to reply (and reply-all).\n}\n\nstruct EmailAttachment {\n contentType @0 :Text; # header is actually content-type\n contentDisposition @1 :Text; # header is actually content-disposition\n contentId @2 :Text; # header is actually content-id\n\n content @3 :Data;\n}\n\nstruct EmailMessage {\n date @0 :Int64; # Nanoseconds since unix epoch.\n\n from @1 :EmailAddress;\n to @2 :List(EmailAddress);\n cc @3 :List(EmailAddress);\n bcc @4 :List(EmailAddress);\n replyTo @5 :EmailAddress; # header is actually reply-to\n # TODO(someday): replyTo should actually be a List(EmailAddress)\n\n messageId @6 :Text; # header is actually message-id\n references @7 :List(Text);\n inReplyTo @8 :List(Text); # header is actually in-reply-to\n\n # TODO(someday): Add list-id.\n\n subject @9 :Text;\n\n # Separate body into text and html fields.\n # Any other content-types will be in the attachments field.\n text @10 :Text;\n html @11 :Text;\n attachments @12 :List(EmailAttachment);\n}\n\ninterface EmailSendPort @0xec831dbf4cc9bcca {\n # Represents a destination for e-mail.\n #\n # Make a Powerbox request for `EmailSendPort` when you want to request permission to send email\n # to the current user. For example, a mailing list app would request this when a user indicates\n # they wish to subscribe to the list.\n #\n # Make a Powerbox offer of an `EmailSendPort` when you want to receive email on that port.\n # The user will be prompted to assign your port to an address. For example, a mailing list app\n # would offer an `EmailSendPort` to the owner during initial setup.\n\n send @0 (email :EmailMessage);\n # Send a message through this port.\n\n hintAddress @1 (address :EmailAddress);\n # Hint to the port that it is now receiving email sent to the given address. The email driver\n # will call this after the port has been bound to an address after being offered through the\n # Powerbox. The purpose is to allow the app to display back to the user what address it is\n # bound to. Implementing this is optional.\n\n struct PowerboxTag {\n # Tag which can be set on `PowerboxDescriptor`s when requesting an `EmailSendPort`.\n\n fromHint @0 :EmailAddress;\n # The user will be offered the ability to override the \"from\" address on emails sent through\n # this port. The application requesting the port may provide `fromHint` to suggest an override\n # address to the user. Do not provide a `fromHint` if you do not want `from` addresses to be\n # overridden, but note that the user may choose to do so anyway.\n #\n # It does not make sense to fill in this field when making a Powerbox offer.\n\n listIdHint @1 :Text;\n # The user will be offered the ability to set the \"list-id\" on emails sent through this port.\n # The application requesting the port may provide 'listIdHint' to suggest a list ID to use.\n # Do not provide a `listIdHint` if you do not want the list ID to be set, but note that the\n # user may choose to set it anyway.\n #\n # It does not make sense to fill in this field when making a Powerbox offer.\n }\n}\n\ninterface VerifiedEmail @0xf88bf102464dfa5a {\n # By default, an app is not told a user's email address. You may, however, request that the user\n # provide their verified email address through the powerbox.\n #\n # First, you need an `EmailVerifier`. See that class for info on how to get one.\n #\n # To verify a user, make a powerbox request for `VerifiedEmail`. In your `PowerboxDescriptor`,\n # set the tag value to a `VerifiedEmail.PowerboxTag` which has `authority` set to the\n # capability returned by your `EmailVerifier`'s `getAuthority()` method. The user will be asked to\n # choose one of their addresses. The Powerbox returns an `VerifiedEmail` for the address they\n # chose. You must then pass this object to `EmailVerifier.verifyEmail()` to verify that\n # the capability really is attached to the user's account and obtain the final address.\n #\n # You might wonder why the `EmailVerifier.verifyEmail()` step is necessary -- why not just\n # have a `getAddress()` method on `VerifiedEmail` itself? The answer is that although the\n # powerbox will only offer the user a choice of addresses associated with their account, the\n # powerbox code runs client-side, and thus a malicious user could inject an arbitrary capability\n # in place of the powerbox's response. So, they could respond with a fake `VerifiedEmail`\n # capability.\n\n struct PowerboxTag {\n # Use this type as the tag value when requesting an VerifiedEmail in order to narrow the\n # choices presented to the user.\n\n verifierId @0 :Data;\n # Value returned by `EmailVerifier.getId()`. Pass this to ensure that only\n # addresses which can be verified by this verifier are offered as options.\n\n address @1 :Text;\n # Specify a complete address (like \"[email protected]\") in a Powerbox request to request that\n # the user verify this specific address and no other. The user will still have the choice to\n # refuse verification, but will not be offered other addresses.\n #\n # This field will NOT be present in the tag returned with the powerbox response, because the\n # field could be spoofed by the user. You must invoke `EmailVerifier.verifyEmail()` to find out\n # the matching address.\n\n domain @2 :Text;\n # Specify a domain (like \"example.com\") in a Powerbox request to require that the user choose\n # an address under the specified domain. The user will still have the choice to refuse\n # verification, but will not be offered addresses under other domains.\n #\n # This field will NOT be present in the tag returned with the powerbox response, because the\n # field could be spoofed by the user. You must invoke `EmailVerifier.verifyEmail()` to find out\n # the matching address.\n }\n}\n\ninterface VerifiedEmailSendPort @0xa3cc885445aed8e9 extends(VerifiedEmail, EmailSendPort) {\n # Make a PowerboxRequest for this type when you want to both verify an email and request\n # the ability to send messages to it.\n\n struct PowerboxTag {\n verification @0 :VerifiedEmail.PowerboxTag;\n port @1 :EmailSendPort.PowerboxTag;\n }\n}\n\ninterface EmailVerifier @0xd458f7ca9d1ba9ff {\n # Object which can verify users' email addresses.\n #\n # To obtain an `EmailVerifier`, do a powerbox request for one, usually during first-time\n # setup of your app. The user will be asked what kinds of address verification mechanisms they\n # wish to trust -- e.g., do they trust that if Github says it has verified an address, it really\n # has, or do they want Sandstorm do directly verify addresses? SECURITY NOTE: The user from whom\n # you request the `EmailVerifier` will have the ability to spoof verifications, so only\n # request it from the grain owner!\n #\n # Once you have a verifier, you can verify a user's address by making a powerbox request for\n # an `VerifiedEmail` from that user; see the docs for `VerifiedEmail` for info.\n\n getId @0 () -> (id :Data);\n # Place the returned value in your `VerifiedEmail.PowerboxTag` when making a powerbox\n # request. This tells the powerbox to filter for options that will be accepted by this\n # `EmailVerifier`.\n #\n # Implementations of EmailVerifier should generate this value randomly to prevent collisions,\n # but note that the ID need not be kept secret, since it's really only a filtering hint.\n\n verifyEmail @1 (tabId :Data, verification :VerifiedEmail) -> (address :Text);\n # Unpack the given verification to read the address that was verified.\n #\n # `tabId` comes from `UiView.newSession()`; verification only succeeds if it was in fact this\n # tab's user whose address was verified. This exists to prevent the following MITM attack: Alice\n # wants to falsely verify to a grain belonging to Carol that she owns Bob's address. So, she\n # creates a grain of her own running an app that requests email verification and sends it to Bob.\n # Bob willingly verifies his email to Alice's grain since Alice already knows his address anyway.\n # However, Alice's grain actually stashes the VerifiedEmail capability. Alice then visits\n # Carol's grain which requests email verification. Alice directs her malicious grain to respond\n # to the powerbox request with Bob's VerifiedEmail. This doesn't work because Bob's\n # VerifiedEmail was created in Bob's tab (against Alice's grain), and therefore when Carol's\n # grain tries to verify it passing Alice's `tabId`, they don't match, and the verification fails.\n}\n\ninterface EmailAgent @0x8b6f158d70cbc773 {\n # Represents the ability to send and receive email as some user.\n #\n # Make a Powerbox request for `EmailAgent` when you want to request the ability to send and\n # receive email under some address. For example, an email client app would request this.\n\n send @0 (email :EmailMessage);\n # Send a message from this user to all the addresses listed in the message's `to`, `cc`, and\n # `bcc` fields. `email.from` is ignored; it will be replaced with the address associated with\n # this capability. `email.bcc` will not be revealed to recipients.\n\n addReceiver @1 (port :EmailSendPort) -> (handle :Util.Handle);\n # Arrange for future mail sent to this user to be delivered to `port`.\n #\n # Drop the returned handle to unsubscribe. This handle is persistent (can be saved as a\n # SturdyRef).\n #\n # Multiple `port`s can be added; each will receive a copy.\n}\n\n# TODO(someday): Support remote mailboxes, e.g. IMAP. Look at Nylas API for design hints!\n",
"ip.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xf44732d435305f86;\n# This file defines Cap'n Proto interfaces for TCP/IP networking.\n#\n# The purpose of these interfaces is to implement \"driver\" applications -- that is, apps which\n# themselves implement raw legacy network protocols (e.g. HTTP, SMTP, XMPP, etc.) and then\n# re-export those protocols as a Cap'n Proto interface with meaningful separation of capabilities.\n# Driver applications generally must be \"approved by the Sandstorm adminsitrator\" because raw\n# network access can be abused in ways that harm the server as a whole. For example, an app which\n# secretly sends spam via SMTP or engages in piracy via Bittorrent could harm the server's\n# reputation, not just the user's.\n#\n# In practice, a driver app is technically just a regular application that makes a Powerbox request\n# for raw network access (represented by the interfaces defined in this file). Only the server\n# administrator normally possesses these capabilities, therefore only the administartor can\n# normally authorize such apps.\n#\n# Of course, a regular user could run a driver app and connect it to fake networking capabilities,\n# e.g. for the purpose of testing, or for use over a fake IP network that only connects to other\n# Sandstorm apps.\n#\n# For simplicity in porting legacy apps, sandstorm-http-bridge can optionally be configured to\n# act as an IP proxy, allowing legacy apps to transparently use IP networking via the standard\n# socket API.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing SystemPersistent = import \"supervisor.capnp\".SystemPersistent;\n\ninterface IpNetwork @0xa982576b7a2a2040 {\n # Capability to connect or send messages to arbitrary destinations on an IP network.\n #\n # A driver app can request this from the Powerbox in order to request \"full outbound network\n # access\". The IpNetwork capability is a dangerous capability that should only be granted to\n # trusted drivers. Only the Sandstorm server administrator is likely to possess this capability.\n\n struct PowerboxTag {\n # Tag to be used in a `PowerboxDescriptor` to describe an `IpNetwork`.\n\n encryption @0 :Encryption;\n # The encryption scheme, if any, on top of which the `IpNetwork` layers its connections\n # and messages.\n\n struct Encryption @0xe2d94cf90fe4078d {\n # Describes an encryption scheme.\n #\n # Capabilities derived from an `IpNetwork` may use this struct in their own powerbox\n # descriptors, either in an explicit `PowerboxTag.encryption` field, like here with\n # `IpNetwork`, or in an independent powerbox tag, marked by this struct's type ID.\n\n union {\n none @0 :Void;\n # No encryption.\n\n tls @1 :Void;\n # Transport Layer Security, using a standard set of certificates.\n }\n }\n }\n\n getRemoteHost @0 (address :IpAddress) -> (host :IpRemoteHost);\n # Get the remote host corresponding to the given address.\n\n getRemoteHostByName @1 (address :Text) -> (host :IpRemoteHost);\n # Like `getRemoteHost()` but parse the address from text and perform a DNS lookup if necessary.\n # Textual representations of IP addresses will also be accepted.\n}\n\nstruct IpAddress {\n # An IPv6 address.\n #\n # IPv4 addresses must be represented using IPv4-mapped IPv6 addresses.\n\n lower64 @0 :UInt64;\n upper64 @1 :UInt64;\n # Bits of the IPv6 address. Since IP is a big-endian spec, the \"lower\" bits are on the right, and\n # the \"upper\" bits on the left. E.g., if the address is \"1:2:3:4:5:6:7:8\", then the lower 64 bits\n # are \"5:6:7:8\" or 0x0005000600070008 while the upper 64 bits are \"1:2:3:4\" or 0x0001000200030004.\n #\n # Note that for an IPv4 address, according to the standard IPv4-mapped IPv6 address rules, you\n # would use code like this:\n # uint32 ipv4 = (octet[0] << 24) | (octet[1] << 16) | (octet[2] << 8) | octet[3];\n # dest.setLower64(0x0000FFFF00000000 | ipv4);\n # dest.setUpper64(0);\n}\n\ninterface IpInterface @0xe32c506ee93ed6fa {\n # Capability to accept connections / messages on a particular network interface.\n #\n # In practice this could represent a single physical network interface, a single local IP\n # address, or \"all interfaces\" (i.e. 0.0.0.0).\n #\n # A driver app can request this from the Powerbox in order to request \"full inbound network\n # access\", i.e. permission to open and listen on any port. The IpInterface capability is a\n # dangerous capability that should only be granted to trusted drivers. Only the Sandstorm server\n # administrator is likely to possess this capability.\n\n listenTcp @0 (portNum :UInt16, port :TcpPort) -> (handle :Util.Handle);\n # Binds `port` to the given TCP port number, so that it will receive any incoming TCP connections\n # to the port.\n\n listenUdp @1 (portNum :UInt16, port :UdpPort) -> (handle :Util.Handle);\n # Binds `port` to the given UDP port number, so that it will receive any incoming UDP datagrams\n # sent to the port.\n}\n\ninterface IpRemoteHost @0x905dd76b298b3130 {\n # Capability to connect / send messages to a particular remote host accessed over an IP network.\n #\n # A driver app can request this form the Powerbox in order to request \"permission to connect to\n # arbitrary ports on a particular host\". While not as dangerous as IpNetwork, this is still a\n # sensitive capability, as connecting to e.g. Google could allow an app to send mass quantities\n # of spam (while perhaps claiming that it is just updating your calendar, or something).\n #\n # Only request an `IpRemoteHost` capability if you need to be able to connect to multiple ports\n # on the host. If you only need to connect to one port, request `TcpPort` or `UdpPort` instead.\n # This way the user can more easily understand what is being requested and can more easily\n # reroute when desired.\n\n getTcpPort @0 (portNum :UInt16) -> (port :TcpPort);\n getUdpPort @1 (portNum :UInt16) -> (port :UdpPort);\n}\n\ninterface TcpPort @0xeab20e1af07806b4 {\n # Capability to connect to a remote network port.\n #\n # An application may request a TcpPort from the Powerbox in order to request permission to\n # form a TCP connection to an arbitrary address.\n #\n # An application may offer a TcpPort to the Powerbox in order to implement a TCP server and\n # request that it be mapped to an address.\n #\n # While intended to represent a real IP address/port, this interface may in fact be offered and\n # received between two apps through the Powerbox, in which case there is in fact no IP address\n # assigned.\n\n connect @0 (downstream :Util.ByteStream) -> (upstream :Util.ByteStream);\n # Open a new byte stream connection. The callee sends bytes to the caller via `downstream`, while\n # the caller sends bytes to the callee via `upstream`. Notice that the caller may start sending\n # bytes via pipelining immediately.\n}\n\ninterface UdpPort @0xc6212e1217d001ce {\n # Like `TcpPort` but for datagrams.\n\n send @0 (message :Data, returnPort :UdpPort);\n # Send a datagram.\n #\n # As always with UDP, successful return does not indicate successful delivery. On the receiving\n # end, a message may be delivered multiple times and/or may be truncated. It is the app's\n # responsibility to deal with ACKs, timeouts, message ordering, de-duplification, and data\n # integrity.\n #\n # `returnPort` may be used to send a direct reply. On the sending side, if the datagram is sent as\n # a real UDP packet, `returnPort` will be bound to an ephemeral port for a short time to receive\n # this reply. If `returnPort` is already bound to a port (either explicitly, or because it was\n # used in a previous `sendDatagram` call), then IP bridge implementation will reuse that binding\n # rather than allocate a new one. Therefore, frequently sending datagrams with the same\n # `returnPort` should have the effect of keeping the real IP address/port constant (this is\n # analogous to how NATs typically handle UDP traffic).\n #\n # TODO(someday): Cap'n Proto should support marking methods as \"fast-but-unreliable\", with all\n # the properties of UDP. Then, this method should be marked as such.\n}\n\nstruct IpPortPowerboxMetadata {\n # When making a Powerbox request for or offer of a `TcpPort` or `UdpPort`, this metadata may be\n # specified to refine the request / offer.\n #\n # TODO(soon): This is currently more of a concept, as we have not yet decided how \"metadata\"\n # should be attached to Powerbox requests or offers.\n\n preferredPortNum @0 :UInt16;\n # The \"standard\" port number for the service being offered / requested.\n #\n # For Powerbox requests, this is used to fill in the port number of the remote service. The\n # user then only needs to fill in a hostname or IP. The user may override the port if desired.\n #\n # For Powerbox offers, this is used to specify the port to which the service ought to be bound,\n # although the user may override it.\n\n preferredHost @1 :Text;\n # If non-empty, contains the port's expected/preferred host name. Like preferredPortNum, this is\n # used to prefill forms, but the user may override. A textual representation of an IP address\n # (v4 or v6) is also allowed here.\n #\n # If possible, design your app so that the powerbox interaction is the point where the hostname\n # is specified in the first place. For example, if your app asks the user to specify a host to\n # connect to, and then immediately makes a powerbox request for that host, consider instead not\n # asking the user for a hostname at all and instead making the Powerbox request right off and\n # letting the user specify the hostname there.\n}\n\ninterface PersistentIpNetwork extends (IpNetwork, SystemPersistent) {}\ninterface PersistentIpInterface extends (IpInterface, SystemPersistent) {}\n",
"persistentuiview.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xfe5c7cde99284f21;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing SystemPersistent = import \"supervisor.capnp\".SystemPersistent;\nusing UiView = import \"grain.capnp\".UiView;\n\ninterface PersistentUiView extends (UiView, SystemPersistent) {}\n# An interface which can be restored into a UiView.\n# Note that when restored by a grain, the UiView restored will not by default carry the `isHuman`\n# pseudopermission, which is required to actually make any calls on a UiView.\n# However, when offered to a user, the user has the `isHuman` pseudopermission, which allows them to\n# open sessions on the UiView.\n#\n# Note that this interface lives in a separate file because while it logically belongs in grain.capnp,\n# SystemPersistent lives in supervisor.capnp, this interface needs to extend both due to limitations\n# in node-capnp regarding instantiating a single type, and capnproto disallows circular imports.\n",
"sandstorm-http-bridge.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014-2015 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xac137d236832bb1e;\n# This file defines interfaces that allow sandstorm-http-bridge to provide apps with access to\n# Sandstorm platform features.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\nusing Grain = import \"grain.capnp\";\nusing Identity = import \"identity.capnp\";\n\ninterface SandstormHttpBridge {\n # Bootstrap interface provided to the app on a Unix domain socket at /tmp/sandstorm-api.\n\n getSandstormApi @0 () -> (api :Grain.SandstormApi);\n # Get the SandstormApi capability that was provided by the supervisor.\n\n getSessionContext @1 (id :Text) -> (context :Grain.SessionContext);\n # Get the SessionContext corresponding to a UiSession. The appropriate `id` value can be read\n # from the X-Sandstorm-Session-Id header inserted by sandstorm-http-bridge.\n\n getSavedIdentity @2 (identityId :Text) -> (identity :Identity.Identity);\n # If BridgeConfig.saveIdentityCaps is true for this app, then you can call this method to fetch\n # the saved identity capability for a particular identityId as passed in the\n # `X-Sandstorm-User-Id` header.\n\n saveIdentity @3 (identity :Identity.Identity);\n # If BridgeConfig.saveIdentityCaps is true for this app, adds the given identity to the\n # grain's database, allowing it to be fetched later with `getSavedIdentity()`.\n}\n",
"update-tool.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0x96c3fff3f4beb8fe;\n# This file contains schemas relevant to the Sandstorm self-updater.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nstruct PublicSigningKey {\n key0 @0 :UInt64;\n key1 @1 :UInt64;\n key2 @2 :UInt64;\n key3 @3 :UInt64;\n # ed25519 public key.\n}\n\nstruct Signature {\n sig0 @0 :UInt64;\n sig1 @1 :UInt64;\n sig2 @2 :UInt64;\n sig3 @3 :UInt64;\n sig4 @4 :UInt64;\n sig5 @5 :UInt64;\n sig6 @6 :UInt64;\n sig7 @7 :UInt64;\n}\n\nconst updatePublicKeys :List(PublicSigningKey) = [\n # List of public keys with which Sandstorm updates are signed. The last key in this list should\n # be used to verify updates. When we \"rotate\" keys, we actually add a new key, but keep signing\n # with the old keys as well, so that existing servers can update.\n\n (key0 = 0x5a2d999e727ba977, key1 = 0x83cea6e0708ccf63, key2 = 0xdf70ccedc4be19bc, key3 = 0x81087ee2db417366),\n];\n\nstruct UpdateSignature {\n # Format of a signature file.\n\n signatures @0 :List(Signature);\n # Signatures corresponding to each key in updatePublicKeys.\n}\n",
"util.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xecd50d792c3d9992;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing DateInNs = Int64;\nusing DurationInNs = UInt64;\n\nstruct KeyValue {\n key @0 :Text;\n value @1 :Text;\n}\n\nstruct LocalizedText {\n # Text intended to be displayed to a user. May be localized to multiple languages.\n #\n # TODO(soon): Maybe instead of packing all translations in here, we should have a message code\n # and parameter substitutions, with the (message code, locale) -> text map stored elsewhere?\n\n defaultText @0 :Text;\n # What to display if no localization matching the user's preferences is available.\n\n localizations @1 :List(Localization);\n # Localized versions of the text.\n\n struct Localization {\n locale @0 :Text; # IETF BCP 47 locale, e.g. \"en\" or \"en-US\".\n text @1 :Text; # Localized text.\n }\n}\n\ninterface Handle {\n # Arbitrary handle to some resource provided by the platform. May or may not be persistent,\n # depending on the use case.\n #\n # To \"drop\" a handle means to discard any references. The purpose of a handle is to detect when\n # it has been dropped and to free the underlying resource and cancel any ongoing operation at\n # that time.\n #\n # A handle can be persistent. Once you have called `save()` on it to obtain a SturdyRef, dropping\n # the live reference will not cancel the operation. You must drop all live references *and*\n # explicitly drop any SturdyRef. Every interface which supports restoring SturdyRefs also\n # has a corresponding `drop()` method for this purpose.\n #\n # Unfortunately, there is no way to ensure that a SturdyRef will eventually be deleted. A grain\n # could, for example, call `save()` and then simply fail to store the SturdyRef anywhere, causing\n # it to be \"leaked\" until such a time as the grain itself is destroyed. Or worse, a whole server\n # could be destroyed in a fire, leaking all SturdyRefs stored therein forever. Apps implementing\n # persistent handles must be designed to account for this, probably by giving the owning user\n # a way to inspect incoming references and remove them manually. Sandstorm automatically provides\n # such an interface for all apps it hosts.\n\n ping @0 ();\n # Checks if the handle is still connected. Call this and check for a DISCONNECTED exception to\n # see if the handle has been disconnected. Servers usually do not implement this method, so any\n # other exception type shoudl be considered to indicate that the handle is still live.\n #\n # This is particularly important when holding a handle to a Sandstorm grain where the handle\n # represents some sort of long-running operation. The grain will shut down if it doesn't receive\n # incoming calls at least every 60 seconds, so you may want to ping() it to keep it alive.\n}\n\ninterface ByteStream {\n # Represents a destination for a stream of bytes. The bytes are ordered, but boundaries between\n # messages are not semantically important.\n #\n # Streams are push-oriented (traditionally, \"output streams\") rather than pull-oriented (\"input\n # streams\") because this most easily allows multiple packets to be in-flight at once while\n # allowing flow control at either end. If we tried to design a pull-oriented stream, it would\n # suffer from problems:\n # * If we used a naive read() method that returns a simple data blob, you would need to make\n # multiple simultaneous calls to deal with network latency. However, those calls could\n # potentially return in the wrong order. Although you could restore order by keeping track of\n # the order in which the calls were made, this would be a lot of work, and most callers would\n # probably fail to do it.\n # * We could instead have a read() method that returns a blob as well as a capability to read the\n # next blob. You would then make multiple calls using pipelining. Even in this case, though,\n # an unpredictable event loop could schedule a pipelined call's return before the parent call.\n # Moreover, the interface would be awkward to use and implement. E.g. what happens if you call\n # read() twice on the same capability?\n\n write @0 (data :Data);\n # Add bytes.\n #\n # It's safe to make overlapping calls to `write()`, since Cap'n Proto enforces E-Order and so\n # the calls will be delivered in order. However, it is a good idea to limit how much data is\n # in-flight at a time, so that it doesn't fill up buffers and block other traffic. On the other\n # hand, having only one `write()` in flight at a time will not fully utilize the available\n # bandwidth if the connection has any significant latency, so parallelizing a few `write()`s is\n # a good idea.\n #\n # Similarly, the implementation of `ByteStream` can delay returning from `write()` as a way to\n # hint to the caller that it should hold off on further writes.\n\n done @1 ();\n # Call after the last write to indicate that there is no more data. If the `ByteStream` is\n # discarded without a call to `done()`, the callee must assume that an error occurred and that\n # the data is incomplete.\n #\n # This will not return until all bytes are successfully written to their final destination.\n # It will throw an exception if any error occurs, including if the total number of bytes written\n # did not match `expectSize()`.\n\n expectSize @2 (size :UInt64);\n # Optionally called to let the receiver know exactly how much data will be written. This should\n # normally be called before the first write(), but if called later, `size` indicates how many\n # more bytes to expect _after_ the call. It is an error by the caller if more or fewer bytes are\n # actually written before `done()`; this also implies that all calls to `expectSize()` must be\n # consistent. The caller will ignore any exceptions thrown from this method, therefore it\n # is not necessary for the callee to actually implement it.\n}\n\ninterface Blob @0xe53527a75d90198f {\n # Represents a large byte blob.\n\n getSize @0 () -> (size :UInt64);\n # Get the total size of the blob. May block if the blob is still being uploaded and the size is\n # not yet known.\n\n writeTo @1 (stream :ByteStream, startAtOffset :UInt64 = 0) -> (handle :Handle);\n # Write the contents of the blob to `stream`.\n\n getSlice @2 (offset :UInt64, size :UInt32) -> (data :Data);\n # Read a slice of the blob starting at the given offset. `size` cannot be greater than Cap'n\n # Proto's limit of 2^29-1, and reasonable servers will likely impose far lower limits. If the\n # slice would cross past the end of the blob, it is truncated. Otherwise, `data` is always\n # exactly `size` bytes (though the caller should check for security purposes).\n #\n # One technique that makes a lot of sense is to start off by calling e.g. `getSlice(0, 65536)`.\n # If the returned data is less than 65536 bytes then you know you got the whole blob, otherwise\n # you may want to switch to `writeTo`.\n}\n\ninterface Assignable(T) {\n # An \"assignable\" -- a mutable memory cell. Supports subscribing to updates.\n\n get @0 () -> (value :T, setter :Setter);\n # The returned setter functions the same as you'd get from `asSetter()` except that it will\n # become disconnected the next time the Assignable is set by someone else. Thus, you may use this\n # to implement optimistic concurrency control.\n\n asGetter @1 () -> (getter :Getter);\n # Return a read-only capability for this assignable, co-hosted with the assignable itself for\n # performance. If the assignable is persistent, the getter is as well.\n\n asSetter @2 () -> (setter :Setter);\n # Return a write-only capability for this assignable, co-hosted with the assignable itself for\n # performance. If the assignable is persistent, the setter is as well.\n\n interface Getter {\n get @0 () -> (value :T);\n\n subscribe @1 (setter :Setter) -> (handle :Handle);\n # Subscribe to updates. Calls the given setter any time the assignable's value changes. Drop\n # the returned handle to stop receiving updates. If `setter` is persistent, `handle` will also\n # be persistent.\n }\n\n interface Setter {\n set @0 (value :T) -> ();\n }\n}\n\ninterface StaticAsset @0xfabb5e621fa9a23f {\n # A file served by the Sandstorm frontend, suitable for embedding e.g. in <img> elements\n # inside of a grain iframe.\n\n enum Protocol {\n # To prevent XSS attacks, we restrict the protocols allowed in static asset URLs. For example,\n # allowing \"javascript:\" URLs would be dangerous because then the static asset could provide\n # abritrary code that would likely be executed in the context of the calling app.\n\n https @0;\n http @1;\n }\n\n getUrl @0 () -> (protocol: Protocol, hostPath :Text);\n # To reconstruct the full URL from the return value, concatenate: `protocol + \"://\" + hostPath`.\n}\n",
"package.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xdf9bc20172856a3a;\n# This file contains schemas relevant to the Sandstorm package format. See also the `spk` tool.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm::spk\");\n\nusing Util = import \"util.capnp\";\nusing Powerbox = import \"powerbox.capnp\";\nusing Grain = import \"grain.capnp\";\nusing ApiSession = import \"api-session.capnp\".ApiSession;\nusing Identity = import \"identity.capnp\";\nusing WebSession = import \"web-session.capnp\".WebSession;\n\nstruct PackageDefinition {\n id @0 :Text;\n # The app's ID string. This is actually an encoding of the app's public key generated by the spk\n # tool, and looks something like \"h37dm17aa89yrd8zuqpdn36p6zntumtv08fjpu8a8zrte7q1cn60\".\n #\n # Normally, `spk init` will fill this in for you. You can use `spk keygen` to generate a new ID\n # if needed. The private key corresponding to each ID is stored in a keyring outside your project\n # directory; see `spk help` for more on this.\n #\n # Note that you can specify an alternative ID to `spk pack` with the `-i` flag. This makes sense\n # when you are doing an unofficial build of an app and don't want to use (or don't have access\n # to) the app's real private key.\n\n manifest @1 :Manifest;\n # Manifest to write as the package's `sandstorm_manifest`. If null, then `sandstorm-manifest`\n # should appear in the file list.\n\n sourceMap @2 :SourceMap;\n # Indicates where to search for file to include in the package.\n\n fileList @3 :Text;\n # Name of a file which itself contains a list of files, one per line, that should be included\n # in the package. Each file should be specified according to its location in the package; the\n # source file will be found by mapping this through `sourceMap`. Each name should be canonical\n # (no \".\", \"..\", or consecutive slashes) and should NOT start with '/'.\n #\n # The file list is automatically generated by `spk dev` based on watching what files are opened\n # by the actual running server. On subsequent runs, new files will be added, but files will never\n # be removed from the list. To reset the list, simply delete it and run `spk dev` again.\n\n alwaysInclude @4 :List(Text);\n # Files and directories that should always be included in the package whether or not they are\n # in the file named by `fileList`. If you name a directory here, its entire contents will be\n # included recursively (this is not the case in `fileList`). Use this list to name files that\n # wouldn't automatically be included, because for whatever reason the server does not actually\n # open them when running in dev mode. This could include runtime dependencies that are too\n # difficult to test fully, or perhaps a readme file or copyright notice that you want people to\n # see if they unpack your package manually.\n\n bridgeConfig @5 :BridgeConfig;\n # Configuration variables for apps that use sandstorm-http-bridge.\n}\n\nstruct Manifest {\n # This manifest file defines an application. The file `sandstorm-manifest` at the root of the\n # application's `.spk` package contains a serialized (binary) instance of `Manifest`.\n #\n # TODO(soon): Maybe this should be renamed. A \"manifest\" is a list of contents, but this\n # structure doesn't contain a list at all; it contains information on how to use the contents.\n\n const sizeLimitInWords :UInt64 = 1048576;\n # The maximum size of the Manifest is 8MB (1M words). This limit is enforced in many places.\n\n appTitle @7 :Util.LocalizedText;\n # The name of this app as it should be displayed to the user.\n\n appVersion @4 :UInt32;\n # Among app packages with the same app ID (i.e. the same `publicKey`), `version` is used to\n # decide which packages represent newer vs. older versions of the app. The sole purpose of this\n # number is to decide whether one package is newer than another; it is not normally displayed to\n # the user. This number need not have anything to do with the \"marketing version\" of your app.\n\n minUpgradableAppVersion @5 :UInt32;\n # The minimum version of the app which can be safely replaced by this app package without data\n # loss. This might be non-zero if the app's data store format changed drastically in the past\n # and the app is no longer able to read the old format.\n\n appMarketingVersion @6 :Util.LocalizedText;\n # Human-readable presentation of the app version, e.g. \"2.9.17\". This will be displayed to the\n # user to distinguish versions. It _should_ match the way you identify versions of your app to\n # users in documentation and marketing.\n\n minApiVersion @0 :UInt32;\n maxApiVersion @1 :UInt32;\n # Min and max API versions against which this app is known to work. `minApiVersion` primarily\n # exists to warn the user if their instance is too old. If the sandstorm instance is newer than\n # `maxApiVersion`, it may engage backwards-compatibility hacks and hide features introduced in\n # newer versions.\n\n metadata @8 :Metadata;\n # Stuff that's not important to actually executing the app, but important to how the app is\n # presented to the user in the Sandstorm UI and app marketplace.\n\n struct Command {\n # Description of a command to execute.\n #\n # Note that commands specified this way are NOT interpreted by a shell. If you want shell\n # expansion, you must include a shell binary in your app and invoke it to interpret the\n # command.\n\n argv @1 :List(Text);\n # Argument list, with the program name as argv[0].\n\n environ @2 :List(Util.KeyValue);\n # Environment variables to set. The environment will be completely empty other than what you\n # define here.\n\n deprecatedExecutablePath @0 :Text;\n # (Obsolete) If specified, will be inserted at the beginning of argv. This is now redundant\n # because you should just specify the program as argv[0]. To be clear, this does not and did\n # never provide a way to make argv[0] contain something other than the executable name, as\n # you can technically do with the `exec` system call.\n }\n\n struct Action {\n input :union {\n none @0 :Void;\n # This action creates a new grain with no input.\n\n capability @1 :List(Powerbox.PowerboxDescriptor);\n # This action creates a new grain from a powerbox offer. When a capability matching the query\n # is offered to the user (e.g. by another application calling SessionContext.offer()), this\n # action will be listed as one of the things the user can do with it.\n #\n # On startup, the platform will call create the first session with\n # `UiView.newOfferSession()`.\n }\n\n command @2 :Command;\n # Command to execute (in a newly-allocated grain) to run this action.\n\n title @3 :Util.LocalizedText;\n # (Obsolete) Title of this action, to display in the action selector. This should no longer\n # be used for new apps.\n\n nounPhrase @5 : Util.LocalizedText;\n # When this action is run, what kind of thing is created? E.g. Etherpad creates a \"document\".\n # Displayed as \"New <nounPhrase>\" in the \"create new grain\" UI.\n\n description @4 :Util.LocalizedText;\n # Description of this action, suitable for help text.\n }\n\n actions @2 :List(Action);\n # Actions which this grain offers.\n\n continueCommand @3 :Command;\n # Command to run to restart an already-created grain.\n}\n\nstruct SourceMap {\n # Defines where to find files that need to be included in a package. This is usually combined\n # with a list of files that the package is expected to contain in order to compile a package.\n # The list of files may come from using \"spk dev\" to\n\n searchPath @0 :List(Mapping);\n # List of directories to map into the package.\n\n struct Mapping {\n # Describes a directory to be mapped into the package.\n\n packagePath @0 :Text;\n # Path where this directory should be mapped into the package. Must be a canonical file name\n # (no \".\" nor \"..\") and must not start with '/'. Omit to map to the package root directory.\n\n sourcePath @1 :Text;\n # Path on the local system where this directory may be found. Relative paths are interpreted\n # relative to the location of the package definition file.\n\n hidePaths @2 :List(Text);\n # Names of files or subdirectories within the directory which should be hidden when mapping\n # this path into the spk. Use only canonical paths here -- i.e. do not use \".\", \"..\", or\n # multiple consecutive slashes. Do not use a leading slash.\n }\n}\n\nstruct BridgeConfig {\n # Configuration variables specific to apps that are using sandstorm-http-bridge. This includes\n # things that need to be communicated to the bridge process before the app starts up, such as\n # permissions.\n\n viewInfo @0 :Grain.UiView.ViewInfo;\n # What to return from the UiView's getViewInfo(). This structure defines, among other things, the\n # list of shareable permissions and roles that apply to this app. See grain.capnp for more details.\n #\n # When a request comes in from the user, sandstorm-http-bridge will set the\n # X-Sandstorm-Permissions header to a comma-delimited list of permission names corresponding to\n # the user's permissions.\n\n apiPath @1 :Text;\n # Specifies a path which will be prefixed to all API requests -- that is, requests coming in\n # through the API endpoint as described in:\n # https://docs.sandstorm.io/en/latest/developing/http-apis/\n #\n # Note that this form of HTTP APIs is old and will eventually be deprecated. In the fantastic\n # future, available APIs should be defined by `powerboxApis`, below. However, as of this writing,\n # `powerboxApis` cannot do everything that old-style HTTP APIs do. Why yes, I did once work at\n # Google, how could you tell?\n #\n # apiPath must end with \"/\".\n #\n # WARNING: Specifying this does NOT prevent access to other paths. Anyone holding an API token\n # can convert it into a sharing token, which provides full access to the grain's web interface.\n # The purpose of apiPath is only to allow you to design your API URL schema independently of\n # your UI's URL schema, which is often convenient. To actually restrict what an API token\n # holder is allowed to do, you MUST use permissions and enforce them for both API and UI\n # requests. See:\n # https://docs.sandstorm.io/en/latest/developing/auth/\n\n saveIdentityCaps @2 :Bool;\n # If true, the first time a new user accesses the grain, the bridge will save the user's Identity\n # capability so that it can be fetched later using `SandstormHttpBridge.getSavedIdentity`. You\n # will probably want to enable this if your app supports notifications.\n\n powerboxApis @3 :List(PowerboxApi);\n struct PowerboxApi {\n # Defines an HTTP API which this application exports, to which other apps can request access\n # via the powerbox.\n #\n # Use this to define APIs to which other applications can request access.\n #\n # Note that this metadata is consulted at the time of a powerbox request. Once the request is\n # complete and a connection has been formed, future changes to the app's manifest will not\n # affect the already-made connection.\n\n name @0 :Text;\n # Symbolic name for this API. This is passed back to the app as the value of the\n # `X-Sandstorm-Api` header, in all requests made to this API. Note that removing an API\n # definition will NOT revoke existing connections formed through the powerbox. So, the app\n # should be prepared to handle all API names that it has ever defined (or, perhaps, return\n # an appropriate error when it receives a request for an API that no longer exists).\n\n displayInfo @1 :Powerbox.PowerboxDisplayInfo;\n # Information for display to the user when representing this API.\n #\n # displayInfo.title in particular will be used when displaying a chooser to the user to choose\n # among the app's available APIs.\n\n path @2 :Text;\n # Specifies the path which will be prefixed to all requests to this API.\n #\n # Like `apiPath` (above), this must end with \"/\". It is perfectly reasonable for the path to be\n # just \"/\", if you consider your app's entire HTTP surface to be an API. However, note that\n # unlike with `apiPath`, restricting a powerbox API to a sub-path actually does prevent\n # consumers of the API from accessing other paths. You may wish to use this to your advantage.\n\n tag @3 :ApiSession.PowerboxTag;\n # Tag defining this API for powerbox matching purposes.\n\n permissions @4 :Identity.PermissionSet;\n # The permissions represented by this API. A user interacting with the powerbox will not have\n # the option of choosing this API unless they possess at least these permissions. Meanwhile,\n # when a request is made to this API, the `Sandstorm-Permissions` header will always contain\n # exactly these permissions, even if the user who made the powerbox connection has greater\n # permissions.\n #\n # If not specified, the `X-Sandstorm-Permissions` header will contain the exact list of\n # permissions that the user had at the time that they formed the connection. Note that if any\n # of these permissions are later revoked from the user, then the API connection will be revoked\n # in whole.\n\n # TODO(someday): Allow non-singleton APIs, for grains that contain many objects. Requires app\n # to implement an embeddable picker UI.\n # TODO(someday): Allow implementing Cap'n Proto APIs via JSON conversion.\n }\n}\n\nstruct Metadata {\n # Data which is not needed specifically to execute the app, but is useful for purposes like\n # marketing and display.\n #\n # Technically, appMarketingVersion and appTitle belong in this category, but they were defined\n # before Metadata became a thing.\n #\n # NOTE: Any changes here which add new blobs may require updating the front-end so that it\n # correctly extracts those blobs into separate assets on install.\n\n icons :group {\n # Various icons to represent the app in various contexts.\n #\n # Each context is associated with a List(Icon). This list contains versions of the same image\n # in varying sizes and formats. When the icon is used, the optimal icon image will be chosen\n # from the list based on the context where it is to be displayed, possibly taking into account\n # parameters like size, display pixel density, and browser image format support.\n\n appGrid @0 :Icon;\n # The icon shown on the app grid, in the \"new grain\" flow.\n #\n # Size: 128x128\n # Data size limit: 64kB\n\n grain @1 :Icon;\n # The icon shown to represent an individual grain, both in the grain table and on the navbar.\n # If omitted, the appGrid icon will be used.\n #\n # Size: 24x24\n # Data size limit: 4kB\n\n market @2 :Icon;\n # The icon shown in the app market grid. If omitted, the appGrid icon will be used.\n #\n # Size: 150x150\n # Data size limit: 64kB\n\n marketBig @18 :Icon;\n # The image shown in the app market when visiting the app's page directly, or when featuring\n # a particular app with a bigger display. If omitted, the regular market icon will be used\n # (raster images may look bad).\n #\n # Size: 300x300\n # Data size limit: 256kB\n }\n\n struct Icon {\n # Represents one icon image.\n\n union {\n unknown @0 :Void;\n # Unknown file format.\n\n svg @1 :Text;\n # Scalable Vector Graphics image. This format is *highly* preferred whenever possible.\n #\n # The uncompressed SVG can be up to 4x the documented size limit, to account for the fact\n # that it will be compressed when served.\n\n png :group {\n # PNG image. You may specify one or both DPI levels.\n\n dpi1x @2 :Data;\n # Normal-resolution PNG. The image's resolution should exactly match the documented\n # viewport size.\n\n dpi2x @3 :Data;\n # Double-resolution PNG for high-dpi displays. Any documented data size limit is also\n # doubled for this PNG. (The size limit is only doubled, not quadrupled, because the size\n # of a compressed image should be a function of total interior edge length, not area.)\n }\n }\n }\n\n website @3 :Text;\n # URL of the app's main web site.\n\n codeUrl @4 :Text;\n # URL of the app's source code repository, e.g. a Github URL.\n #\n # This field is required if the app's license requires redistributing code (such as the GPL),\n # but is optional otherwise.\n\n license :group {\n # How is this app licensed?\n #\n # Example usage for open source licenses:\n #\n # license = (openSource = apache2, notices = (defaultText = embed \"notices.txt\")),\n #\n # Example usage for proprietary licenses:\n #\n # license = (proprietary = (defaultText = embed \"license.txt\"),\n # notices = (defaultText = embed \"notices.txt\")),\n\n union {\n none @5 :Void;\n # No license. Default copyright rules apply; e.g. redistribution is prohibited. See:\n # http://choosealicense.com/no-license/\n #\n # \"None\" does NOT mean \"public domain\". See `publicDomain` below.\n\n openSource @6 :OpenSourceLicense;\n # Indicates an OSI-approved open source license.\n #\n # If you choose such a license, the license title will be displayed with your app on the app\n # market, and users who specify they want to see only open source apps will see your app.\n\n proprietary @7 :Util.LocalizedText;\n # Full text of a non-OSI-approved license.\n #\n # Proprietary licenses usually not only restrict copying but also place limitations on *use*\n # of the app. In other words, while open source licenses grant users additional freedoms\n # compared to default copyright rules, proprietary licenses impose additional restrictions.\n #\n # Because of this, the user must explicitly agree to the license. Sandstorm will display the\n # license to the user and ask them to agree before they can start using the app.\n #\n # If your license does not require such approval -- because it does not add any restrictions\n # beyond default copyright protections -- consider whether it would make sense to use `none`\n # instead; this will avoid prompting the user.\n\n publicDomain @8 :Util.LocalizedText;\n # Indicates that the app is placed in the public domain; you place absolutely no restrictions\n # on its use or distribution. The text is your public domain dedication statement. Please\n # note that public domain is not recognized in all jurisdictions, therefore using public\n # domain is widely considered risky. The Open Source Initiative recommends using a permissive\n # license like MIT's rather than public domain. unlicense.org provides resources to help you\n # use public domain; it is highly recommended that you read it before using this.\n }\n\n notices @9 :Util.LocalizedText;\n # Contains any third-party copyright notices that the app is required to display, for example\n # due to use of third-party open source libraries.\n }\n\n categories @10 :List(Category);\n # List of categories/genres to which this app belongs, sorted with best fit first. See the\n # `Category` enum below.\n #\n # You can list multiple categories, but note that as with all things the app market moderators\n # may ask you to make changes, e.g. if you list categories that don't fit or seem spammy.\n\n author :group {\n # Fields relating to the author of this app.\n #\n # The \"author\" might be a human, but could also be a company, or a pseudo-identity created to\n # represent the app itself.\n #\n # It is extremely important to users that they be able to verify the author's identity in a way\n # that is not susceptible to spoofing or forgery. Therefore, we *only* identify the author by\n # PGP key. Various PGP infrastructure exists which can be used to determine the author's\n # identity based on their PGP key. For example, Keybase.io has done a really good job of\n # connecting PGP keys to other Internet identities in a verifiable way.\n\n upstreamAuthor @19 :Text;\n # Name of the original primary author of this app, if it is different from the person who\n # produced the Sandstorm package. Setting this implies that the author connected to the PGP\n # signature only \"ported\" the app to Sandstorm.\n\n contactEmail @11 :Text;\n # Email address to contact for any issues with this app. This includes end-user support\n # requests as well as app store administrator requests, so it is very important that this be a\n # valid address with someone paying attention to it.\n\n pgpSignature @12 :Data;\n # PGP signature attesting responsibility for the app ID. This is a binary-format detached\n # signature of the following ASCII message (not including the quotes, no newlines, and\n # replacing <app-id> with the standard base-32 text format of the app's ID):\n #\n # \"I am the author of the Sandstorm.io app with the following ID: <app-id>\"\n #\n # You can create a signature file using `gpg` like so:\n #\n # echo -n \"I am the author of the Sandstorm.io app with the following ID: <app-id>\" |\n # gpg --sign > pgp-signature\n #\n # To learn how to set up gpg, visit Keybase (https://keybase.io) -- they have excellent\n # documentation and tools. Moreover, if you create a Keybase account for your key and follow\n # Keybase's instructions to link it to other social accounts (like your Github account), then\n # the Sandstorm app install flow and app market will present this information to the user as\n # \"verified\".\n }\n\n pgpKeyring @13 :Data;\n # A keyring in GPG keyring format containing all public keys needed to verify PGP signatures in\n # this manifest (as of this writing, there is only one: `author.pgpSignature`).\n #\n # To generate a keyring containing just your public key, do:\n #\n # gpg --export <key-id> > keyring\n #\n # Where `<key-id>` is a PGP key ID or email address associated with the key.\n\n description @14 :Util.LocalizedText;\n # The app's description in Github-flavored Markdown format, to be displayed e.g.\n # in an app store. Note that the Markdown is not permitted to cotnain HTML nor image tags (but\n # you can include a list of screenshots separately).\n\n shortDescription @15 :Util.LocalizedText;\n # A very short (one-to-three words) description of what the app does. For example,\n # \"Document editor\", or \"Notetaking\", or \"Email client\". This will be displayed under the app\n # title in the grid view in the app market.\n\n screenshots @16 :List(Screenshot);\n # Screenshots to use for marketing purposes.\n\n struct Screenshot {\n width @0 :UInt32;\n height @1 :UInt32;\n # Width and height of the screenshot in \"device-independent pixels\". The actual width and\n # height of the image is in the image data, but this width and height is used to decide how\n # much to scale the image for it to \"look right\". Typically, a screenshot taken on a high-DPI\n # display should specify this width and height as half of the actual image width and height.\n #\n # The market is under no obligation to display images with any particular size; these are just\n # hints.\n\n union {\n unknown @2 :Void;\n # Unknown file format.\n\n png @3 :Data;\n # PNG-encoded image data. Usually preferred for screenshots.\n\n jpeg @4 :Data;\n # JPEG-encoded image data. Preferred for screenshots that contain photographs or the like.\n }\n }\n\n changeLog @17 :Util.LocalizedText;\n # Documents the history of changes in Github-flavored markdown format (with the same restrictions\n # as govern `description`). We recommend formatting this with an H1 heading for each version\n # followed by a bullet list of changes.\n}\n\nstruct OsiLicenseInfo {\n id @0 :Text;\n # The file name of the license at opensource.org, i.e. such that the URL can be constructed as:\n # http://opensource.org/licenses/<id>\n\n title @1 :Text;\n # Display title for app market. E.g. \"Apache License 2.0\".\n\n requireSource @2 :Bool = false;\n # Whether or not you are required to provide a `codeUrl` when specifying this license.\n}\n\nannotation osiInfo @0x9476412d0315d869 (enumerant) :OsiLicenseInfo;\n# Annotation applied to each item in the OpenSourceLicense enum.\n\nenum OpenSourceLicense {\n # Identities an OSI-approved Open Source license. Apps which claim to be \"open source\" must use\n # one of these licenses.\n\n invalid @0; # Sentinel value; do not choose this.\n\n # Recommended licenses, especially for new code. These four licenses cover the spectrum of open\n # source license mechanics and are widely recognized and understood.\n mit @1 $osiInfo(id = \"MIT\" , title = \"MIT License\");\n apache2 @2 $osiInfo(id = \"Apache-2.0\", title = \"Apache License v2\");\n gpl3 @3 $osiInfo(id = \"GPL-3.0\" , title = \"GNU GPL v3\", requireSource = true);\n agpl3 @4 $osiInfo(id = \"AGPL-3.0\" , title = \"GNU AGPL v3\", requireSource = true);\n\n # Other popular general-purpose licenses.\n bsd3Clause @5 $osiInfo(id = \"BSD-3-Clause\", title = \"BSD 3-Clause\");\n bsd2Clause @6 $osiInfo(id = \"BSD-2-Clause\", title = \"BSD 2-Clause\");\n gpl2 @7 $osiInfo(id = \"GPL-2.0\" , title = \"GNU GPL v2\", requireSource = true);\n lgpl2 @8 $osiInfo(id = \"LGPL-2.1\" , title = \"GNU LGPL v2.1\", requireSource = true);\n lgpl3 @9 $osiInfo(id = \"LGPL-3.0\" , title = \"GNU LGPL v3\", requireSource = true);\n isc @10 $osiInfo(id = \"ISC\" , title = \"ISC License\");\n\n # Popular licenses associated with specific languages.\n artistic2 @11 $osiInfo(id = \"Artistic-2.0\", title = \"Artistic License v2\");\n python2 @12 $osiInfo(id = \"Python-2.0\" , title = \"Python License v2\");\n php3 @13 $osiInfo(id = \"PHP-3.0\" , title = \"PHP License v3\");\n\n # Popular licenses associated with specific projects or companies.\n mpl2 @14 $osiInfo(id = \"MPL-2.0\" , title = \"Mozilla Public License v2\", requireSource = true);\n cddl @15 $osiInfo(id = \"CDDL-1.0\", title = \"CDDL\", requireSource = true);\n epl @16 $osiInfo(id = \"EPL-1.0\" , title = \"Eclipse Public License\", requireSource = true);\n cpal @17 $osiInfo(id = \"CPAL-1.0\" , title = \"Common Public Attribution License\", requireSource = true);\n zlib @18 $osiInfo(id = \"Zlib\" , title = \"Zlib/libpng License\");\n\n # Is your preferred license not on the list? We are happy to add any OSI-approved license; that\n # is, anything on this page:\n # http://opensource.org/licenses/alphabetical\n #\n # Feel free to send a pull request adding yours.\n}\n\nstruct AppId {\n id0 @0 :UInt64;\n id1 @1 :UInt64;\n id2 @2 :UInt64;\n id3 @3 :UInt64;\n}\n\nstruct PackageId {\n id0 @0 :UInt64;\n id1 @1 :UInt64;\n}\n\nstruct VerifiedInfo {\n # `spk verify --capnp` writes this to stdout. Also, `spk verify --details` writes a JSON version\n # of this, with large `Data` and `Text` fields removed and `LocalizedText` simplified to their\n # `defaultText`.\n\n appId @0 :AppId;\n packageId @1 :PackageId;\n # App and package ID computed from package file signature and hash.\n\n title @2 :Util.LocalizedText;\n version @3 :UInt32;\n marketingVersion @4 :Util.LocalizedText;\n\n authorPgpKeyFingerprint @5 :Text;\n\n metadata @6 :Metadata;\n # Stuff extracted directly from manifest.\n}\n\nstruct CategoryInfo {\n title @0 :Text;\n}\n\nannotation categoryInfo @0x8d51dd236606d205 (enumerant) :CategoryInfo;\n\nenum Category {\n # ------------------------------------\n # \"Meta\": communication & coordination\n\n productivity @1 $categoryInfo(title = \"Productivity\");\n # Apps which manage productivity -- i.e. the \"meta\" apps you use to \"get organized\", NOT the apps\n # you use to actually produce content.\n #\n # Examples: Note-taking, to-dos, calendars, kanban boards, project management, team management.\n #\n # NON-examples: Document editors (-> office), e-mail (-> communications).\n\n communications @2 $categoryInfo(title = \"Communications\");\n # Email, chat, conferencing, etc. Things that you use primarily to communicate, not to organize.\n\n social @3 $categoryInfo(title = \"Social\");\n # Social networking. Overlaps with communication, but focuses on organizing a network of people\n # and surfacing content and interactions from your network that aren't explicitly addressed\n # to you.\n\n # ------------------------------------\n # Content creation\n\n webPublishing @4 $categoryInfo(title = \"Web Publishing\");\n # Tools for publishing web sites and blogs.\n\n office @5 $categoryInfo(title = \"Office\");\n # Tools for the office: editors for documents, spreadsheets, presentations, etc.\n\n developerTools @6 $categoryInfo(title = \"DevTools\");\n # Tools for software engineering: source control, test automation, compilers, IDEs, etc.\n\n science @7 $categoryInfo(title = \"Science\");\n # Tools for scientific / academic pursuits: data gathering, data processing, paper publishing,\n # etc.\n\n graphics @10 $categoryInfo(title = \"Graphics\");\n # Tools for creating graphics / visual art.\n\n # ------------------------------------\n # Content consumption\n\n media @8 $categoryInfo(title = \"Media\");\n # Content *consumption*: Apps that aren't used to create content, but are used to display and\n # consume it. Music players, photo galleries, video, feed readers, etc.\n\n games @9 $categoryInfo(title = \"Games\");\n # Games.\n\n # ------------------------------------\n\n other @0 $categoryInfo(title = \"Other\");\n # Use if nothing else fits -- but consider sending us a pull request to add a better category!\n}\n\n# ==============================================================================\n# Below this point is not interesting to app developers.\n#\n# TODO(cleanup): Maybe move elsewhere?\n\nstruct KeyFile {\n # A public/private key pair, as generated by libsodium's crypto_sign_keypair.\n #\n # The keyring maintained by the spk tool contains a sequence of these.\n #\n # TODO(someday): Integrate with desktop environment's keychain for more secure storage.\n\n publicKey @0 :Data;\n privateKey @1 :Data;\n}\n\nconst magicNumber :Data = \"\\x8f\\xc6\\xcd\\xef\\x45\\x1a\\xea\\x96\";\n# A sandstorm package is a file composed of two messages: a `Signature` and an `Archive`.\n# Additionally, the whole file is XZ-compressed on top of that, and the XZ data is prefixed with\n# `magicNumber`. (If a future version of the package format breaks compatibility, the magic number\n# will change.)\n\nstruct Signature {\n # Contains a cryptographic signature of the `Archive` part of the package, along with the public\n # key used to verify that signature. The public key itself is the application ID, thus all\n # packages signed with the same key will be considered to be different versions of the same app.\n\n publicKey @0 :Data;\n # A libsodium crypto_sign public key.\n #\n # libsodium signing public keys are 32 bytes. The application's ID is simply a textual\n # representation of this key.\n\n signature @1 :Data;\n # libsodium crypto_sign signature of the sha512 hash of the `Archive` part of the package\n # (i.e. the package file minus the header).\n}\n\nstruct Archive {\n # A tree of files. Used to represent the package contents.\n\n files @0 :List(File);\n\n struct File {\n name @0 :Text;\n # Name of the file.\n #\n # Must not contain forward slashes nor NUL characters. Must not be \".\" nor \"..\". Must not\n # be the same as any other file in the directory.\n\n lastModificationTimeNs @5 :Int64;\n # Modification timestamp to apply to the file after unpack. Measured in nanoseconds.\n\n union {\n regular @1 :Data;\n # Content of a regular file.\n\n executable @2 :Data;\n # Content of an executable.\n\n symlink @3 :Text;\n # Symbolic link path. The link will be interpreted in the context of the sandbox, where the\n # archive itself mounted as the root directory.\n\n directory @4 :List(File);\n # A subdirectory containing a list of files.\n }\n }\n}\n",
"activity.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xa4e001d4cbcf33fa;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing Identity = import \"identity.capnp\";\n\nstruct ActivityEvent {\n # Describes an event in a grain's activity feed / log.\n #\n # Call SessionContext.activity() to post new activity. The activity is attributed to the user\n # whose SessionContext was used.\n\n path @0 :Text;\n # Path (as in, URL) within the grain where the user can see this activity. Users inspecting the\n # event will be linked to this location. Visiting this path implicitly marks the event as \"read\".\n #\n # This should NOT include a leading '/'. (So, an empty string -- the default -- goes to the grain\n # root).\n\n thread @4 :ThreadInfo;\n # If this event is a member of a \"thread\", information about that thread. For example, in an\n # issue tracker app, all comments on an issue would be part of the same \"thread\". Threads are\n # important for deciding who gets notified and for grouping those notifications: a user might\n # subscribe to a particular thread, and e.g. email notifications related to a thread may be\n # designed to appear as a single email thread.\n\n struct ThreadInfo {\n path @0 :Text;\n # Like ActivityEvent.path, but identifies the path to the thread in general. For subscription\n # purposes, a thread must be uniquely identified by its path.\n\n title @1 :Util.LocalizedText;\n # The title of the thread, e.g. for use in an email subject line. Note that if a thread's title\n # changes, it may cause email notifications related to the therad to form a new thread, since\n # email clients commonly create email threads based on subject line.\n }\n\n notification @1 :NotificationDisplayInfo;\n # Optional metadata used to render a notification about this event. This metadata is not stored\n # in the activity log long-term. It is used e.g. to construct a notification email message or\n # to display in the notification \"bell\" menu (discarded once the notification is dismissed).\n #\n # It is OK to leave this null for simple events, especially events that don't by default send\n # notifications.\n\n type @2 :UInt16;\n # Event type; index into UiView.ViewInfo.eventTypes. Users are able to choose which types of\n # events should notify them.\n\n users @3 :List(User);\n # List of user identities connected to this event.\n\n struct User {\n # Information about a specific user's relationship with this event. At least one of the fields\n # other than `identityId` should be non-default, otherwise listing the user has no purpose.\n\n identity @0 :Identity.Identity;\n\n mentioned @1 :Bool;\n # This user is explicitly \"mentioned\" by this event, e.g. like an @-mention on Twitter or\n # GitHub. In the activity log, the event may explicitly show who was mentioned, and mentioned\n # users may be notified even if they are not explicitly subscribed to the event.\n #\n # Note that if you want a user to be notified but they *aren't* actually \"mentioned\" by the\n # event, you may want to use `subscribed`, below, instead. As a rule of thumb, think about\n # how to complete this sentence: \"You received this notification because _______\" If the blank\n # should say \"you were mentioned\", then set `mentioned = true`. If it would say \"you are\n # subscribed to this thread\" (or something like that), set `subscribed = true`.\n\n subscribed @3 :Bool;\n # Set true if the application manages a concept of \"subscriptions\" internally (rather than\n # letting Sandstorm do it), and that according to this internal computation, the user is\n # \"subscribed\" to this event. The effect of this is that the user will be notified of the\n # event even though it doesn't specifically \"mention\" them. The user may be informed that they\n # are being notified because they are subscribed.\n #\n # Generally, an app should *not* use this field if it uses `autoSubscribeToThread`,\n # `autoSubscribeToGrain`, or the Sandstorm APIs for notification subscriptions. Only use this\n # field if your app is implementing its own notion of subscriptions.\n\n canView @2 :Bool;\n # This user can view this event *even if* they do not meet the `requiredPermission` in the\n # type definition. (However, if the user has no access to the grain at all, they still will\n # not see the event.) This flag is useful when the app is doing its own internal access control\n # rather than relying strictly on Sandstorm permissions.\n }\n}\n\nstruct ActivityTypeDef {\n name @0 :Text;\n # Name of the type, used as an identifier for the type in cases where string names\n # are preferred. These names will never be used in Cap'n Proto interfaces, but could show up in\n # HTTP or JSON translations.\n #\n # The name must be a valid identifier (alphanumerics only, starting with a letter) and must be\n # unique among all types defined for a particular UiView.\n\n verbPhrase @1 :Util.LocalizedText;\n # Text of a verb phrase describing what the acting user did, e.g.:\n # * \"edited document\"\n # * \"created new comment\"\n # * \"replied to comment\"\n #\n # The activity log, when displayed, may contain text like:\n #\n # Kenton Varda - 3 hours ago\n # * edited document x13\n # * created new comment\n # * replied to comment x2\n # Jade Wang - 2 hours ago\n # * replied to comment x3\n # * edited document x5\n\n description @2 :Util.LocalizedText;\n # Prose describing what this activity type means, suitable for a tool tip or similar help text.\n # Optional.\n\n requiredPermission :union {\n # Who is allowed to observe events of this type?\n\n everyone @3 :Void;\n # All users who have any access to this grain are allowed to observe this event.\n\n permissionIndex @4 :UInt16;\n # Users who have the given permission are allowed to observe this event.\n\n explicitList @5 :Void;\n # Only users explicitly listed.\n }\n\n obsolete @6 :Bool = false;\n # If true, this activity type was relevant in a previous version of the application but is no\n # longer used. The activity type will be hidden from the notification settings (and any events\n # of this type will not generate notifications).\n\n # The options below are hints controlling how users are notified of events. Note that these are\n # only hints; a user can potentially override whether or not a particular event causes a\n # notification through a variety of mechanisms. However, these hints are designed to be good\n # defaults.\n\n notifySubscribers @7 :Bool;\n # Should subscribers to this event (including subscribers to the event's thread, if any, and\n # subscribers to the event's grain) receive a notification of this event, by default?\n #\n # Note that when the user explicitly subscribes through the UI, they will have the opportunity\n # to choose exactly which event types they want to produce notifications. Moreover, when an app\n # provides a \"subscribe\" button in its own UI, and the user clicks it, the app can specify\n # different defaults that should apply to that button.\n #\n # Therefore, the `notifySubscribers` bit primarily serves two purposes:\n # - It applies to auto-subscriptions as created due to the `autoSubscribeToThread` or\n # `autoSubscribeToGrain` bits (below).\n # - It applies when an update to the app defines a new type of event. Users who are subscribed\n # to other kinds of notifications will be subscribed to the new notification type if and only\n # if it has `notifySubscribers = true`.\n\n autoSubscribeToThread @8 :Bool;\n # Should the author of this event automatically become subscribed to the thread of which it is\n # a part? (If the event has no threadPath, this option has no effect.)\n #\n # Such an automatic subscription specifically subscribes the user to events which have\n # `notifySubscribers = true` (above).\n\n autoSubscribeToGrain @9 :Bool;\n # Should the author of this event automatically become subscribed to the grain?\n #\n # Such an automatic subscription specifically subscribes the user to events which have\n # `notifySubscribers = true` (above).\n\n suppressUnread @10 :Bool;\n # If true, this kind of activity does not cause the grain to be marked \"unread\". This is useful\n # for activities that should be logged but don't need attention.\n}\n\nstruct NotificationDisplayInfo {\n caption @0 :Util.LocalizedText;\n # Text to display inside the notification box.\n\n # TODO(someday): \"Body\" containing extended text, for the body of an email or perhaps for display\n # in the bell menu after the user clicks on the notification (Google+ style).\n # TODO(someday): Support notifications that can receive text replies. The replies are delivered\n # to a provided capability. When notifications are delivered via email, Sandstorm can\n # automatically support email replies. When notifications are delivered via the bell menu,\n # Sandstorm can render an inline reply textarea (like Google+ notifications).\n # TODO(someday): Support rich interactive notifications, e.g. the ability to play/pause music\n # via buttons.\n}\n\ninterface NotificationTarget @0xf0f87337d73020f0 {\n # Represents a destination for notifications; usually, a user.\n #\n # TODO(someday): Expand on this and move it into `grain.capnp` when notifications are\n # fully-implemented.\n\n addOngoing @0 (displayInfo :NotificationDisplayInfo, notification :OngoingNotification)\n -> (handle :Util.Handle);\n # Sends an ongoing notification to the notification target. `notification` must be persistent.\n # The notification is removed when the returned `handle` is dropped. The handle is persistent.\n}\n\ninterface OngoingNotification @0xfe851ddbb88940cd {\n # Callback interface passed to the platform when registering a persistent notification.\n\n cancel @0 ();\n # Informs the notification creator that the user has requested cancellation of the task\n # underlying this notification.\n #\n # In the case of a `SandstormApi.stayAwake()` notification, after `cancel()` is called, the app\n # will no longer be held awake, so should prepare for shutdown.\n #\n # TODO(someday): We could allow the app to return some text to display to the user asking if\n # they really want to shut down.\n}\n",
"backend.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xdcbc0d702b1b47a5;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing Package = import \"package.capnp\";\nusing Supervisor = import \"supervisor.capnp\".Supervisor;\nusing SandstormCore = import \"supervisor.capnp\".SandstormCore;\nusing GrainInfo = import \"grain.capnp\".GrainInfo;\n\nusing WebSession = import \"web-session.capnp\".WebSession;\nusing ApiSession = import \"api-session.capnp\".ApiSession;\n\ninterface Backend {\n # Interface that thet Sandstorm front-end uses to talk to the \"back end\", i.e. the container\n # scheduler. While Sandstorm is running, the backend interface is exported as a socket at\n # \"/var/sandstorm/socket/backend\".\n\n const socketPath :Text = \"/var/sandstorm/socket/backend\";\n # TODO(cleanup): When the experimental gateway is enabled, we also use a new approach to\n # connecting components using socketpairs instead of paths on-disk, making this constant\n # obsolete. Delete it once the gateway is enabled everywhere.\n\n ping @14 ();\n # Just returns. Used to verify that the connection to the back-end is alive and well.\n\n # ----------------------------------------------------------------------------\n\n startGrain @0 (ownerId :Text, grainId :Text, packageId :Text,\n command :Package.Manifest.Command, isNew :Bool,\n devMode :Bool = false, mountProc :Bool = false)\n -> (supervisor :Supervisor);\n # Start a grain.\n\n getGrain @1 (ownerId :Text, grainId :Text) -> (supervisor :Supervisor);\n # Get the grain if it's running, or throw a DISCONNECTED exception otherwise.\n\n deleteGrain @2 (ownerId :Text, grainId :Text);\n # Delete a grain from disk. Succeeds silently if the grain doesn't exist.\n\n transferGrain @12 (ownerId :Text, grainId :Text, newOwnerId :Text);\n # Transfer a grain's ownership.\n\n deleteUser @13 (userId :Text);\n # Delete an entire user. May or may not delete grains.\n\n # ----------------------------------------------------------------------------\n\n installPackage @3 () -> (stream :PackageUploadStream);\n interface PackageUploadStream extends(Util.ByteStream) {\n saveAs @0 (packageId :Text) -> (appId :Text, manifest :Package.Manifest,\n authorPgpKeyFingerprint :Text);\n # `authorPgpKeyFingerprint` is present only if the signature is valid, and is null if there\n # is no signature. (Invalid signature throws exception.)\n }\n\n tryGetPackage @4 (packageId :Text) -> (appId :Text, manifest :Package.Manifest,\n authorPgpKeyFingerprint :Text);\n # Get info from an already-installed package. Return values are null if the package doesn't\n # exist.\n\n deletePackage @5 (packageId :Text);\n # Delete a package from disk. Succeeds silently if the package doesn't exist.\n\n # ----------------------------------------------------------------------------\n # backups\n\n backupGrain @6 (backupId :Text, ownerId :Text, grainId :Text, info :GrainInfo);\n # Makes a .zip of the contents of the given grain and stores it as a backup file.\n\n restoreGrain @7 (backupId :Text, ownerId :Text, grainId :Text) -> (info :GrainInfo);\n # Unpack a stored backup into a new grain.\n\n uploadBackup @8 (backupId :Text) -> (stream :Util.ByteStream);\n # Upload a zip to create a new backup. If `stream.done()` does not get called and return\n # successfully, the backup wasn't saved.\n\n downloadBackup @9 (backupId :Text, stream :Util.ByteStream);\n # Download a stored backup, writing it to `stream`.\n\n deleteBackup @10 (backupId :Text);\n # Delete a stored backup from disk. Succeeds silently if the backup doesn't exist.\n\n # ----------------------------------------------------------------------------\n\n getUserStorageUsage @11 (userId :Text) -> (size :UInt64);\n # Returns the number of bytes of data in storage attributed to the given user.\n #\n # This method is not implemented by the single-machine version of Sandstorm, which does not track\n # per-user storage quotas.\n\n getGrainStorageUsage @15 (ownerId :Text, grainId :Text) -> (size :UInt64);\n # Returns the number of bytes of data in storage attributed to the given grain.\n #\n # On single-machine Sandstorm, this walks the directory tree, which may be slow. Therefore,\n # it is recommended that this not be called often.\n}\n\ninterface GatewayRouter {\n # Interface which the gateway (C++ code which directly handles HTTP and other traffic) uses to\n # call into Sandstorm's business logic (Node.js process) in order to figure out how to route\n # things.\n #\n # (The Gateway actually conencts to the backend first, which gives it a GatewayRouter as the\n # bootstrap capability. The backend hooks that capability up to the shell, making sure to update\n # the routing any time the shell dies and restarts.)\n #\n # Note that the gateway also makes direct HTTP/WebSocket and SMTP connections for traffic that\n # it does not know how to handle directly.\n\n openUiSession @0 (sessionCookie :Text, params :WebSession.Params)\n -> (session :WebSession, loadingIndicator :Util.Handle, parentOrigin :Text);\n # Given a sandstorm-sid cookie value for a UI session, find the WebSession to handle requests.\n #\n # The gateway may cache the session capability, associated with this cookie value, for as long\n # as it wants. However, session will become disconnected if the grain shuts down or if the user's\n # privileges are revoked. In that case, the gateway will need to discard the capability and\n # request a new one.\n #\n # While `loadingIndicator` is held, the user will see a loading indicator on their screen. Drop\n # this capability when the first HTTP response is received from the app to make the loading\n # indicator go away.\n #\n # `parentOrigin` is the origin permitted to frame this UI session. E.g. Content-Security-Policy\n # frame-ancestors should be used to block clickjacking.\n\n openApiSession @1 (apiToken :Text, params :ApiSession.Params) -> (session :ApiSession);\n # Given a token from an `Authorization` header, find the ApiSession to handle requests.\n #\n # The gateway may cache the session capability, associated with this token, for as long as it\n # wants. However, session will become disconnected if the grain shuts down or if the user's\n # privileges are revoked. In that case, the gateway will need to discard the capability and\n # request a new one.\n #\n # Generally, traffic on an ApiSession will force the grain to stay running. This differs from UI\n # sessions, where the Sandstorm shell keeps track of which grains are open in tabs and decides\n # whether their servers need to keep running.\n\n keepaliveApiToken @8 (apiToken :Text, durationMs :UInt32);\n # Bumps the timer on a self-destructing API token.\n\n getApiHostResource @7 (hostId :Text, path :Text)\n -> (resource :StaticResource);\n # Get info to respond to a GET request on an API host, without need for a token. If `resource`\n # is null, then a 401 should be returned instead to induce authentication.\n\n struct StaticResource {\n type @0 :Text;\n language @1 :Text;\n encoding @2 :Text;\n body @3 :Data;\n }\n\n getApiHostOptions @6 (hostId :Text) -> (dav :List(Text));\n # Get info to respond to an OPTIONS request on an API host, without need for a token.\n\n getStaticAsset @2 (id :Text) -> (content :Data, type :Text, encoding :Text);\n # Look up the content of a static asset by ID. `type` and `encoding` are the values for the\n # `Content-Type` and `Content-Encoding` headers, respectively.\n\n getStaticPublishingHost @3 (publicId :Text) -> (supervisor :Supervisor);\n # Maps a grain's \"public ID\" to a grain supervisor, whose getWwwFileHack() method will be used\n # to host static files.\n\n routeForeignHostname @4 (hostname :Text) -> (info :ForeignHostnameInfo);\n # Called when the gateway receives a request for a hostname that doesn't match any of the\n # expected hostname patterns, to figure out what it is.\n\n struct ForeignHostnameInfo {\n union {\n unknown @0 :Void;\n # This is not a known host.\n\n staticPublishing @1 :Text;\n # It's a static publishing host. Value is the public ID.\n\n standalone @2 :Void;\n # It's a standalone host. HTTP requests should be routed directly to Node business logic.\n }\n\n ttlSeconds @3 :UInt32;\n # How long the receiver can safely cache this lookup result.\n }\n\n subscribeTlsKeys @5 (callback :TlsKeyCallback);\n # Retrieves the current TLS key and certificate and subscribes to future changes to these.\n #\n # This method does not return unless disconnected.\n\n interface TlsKeyCallback {\n setKeys @0 (key :Text, certChain :Text);\n # Sets the current TLS key and certificate, which will be used for all incoming connections\n # until setKeys() is called again.\n #\n # If `key` and `certChain` are null, the shell is informing the gateway that no TLS keys are\n # configured at all.\n #\n # If PRIVATE_KEY_PASSWORD is set in sandstorm.conf, then `key` is expected to be encrypted with\n # that password. This provides a little bit of additional security in that the password is\n # never revealed to the shell process nor to Mongo.\n }\n\n # TODO(someday): We could possibly eliminate the need for any HTTP traffic to Node by serving\n # static assets directly from the gateway and by opening the DDP WebSocket over Cap'n Proto.\n # However, this might not be a win until Cap'n Proto is implemented in native Javascript on the\n # Node side.\n}\n\ninterface SandstormCoreFactory {\n # Interface that the Sandstorm front-end exports to the backend in order to expose business\n # logic hooks.\n #\n # TODO(cleanup): Rename to something more appropriate, now that this does more than construct\n # SansdtormCores.\n\n getSandstormCore @0 (grainId :Text) -> (core :SandstormCore);\n # Create a SandstormCore for a grain. Eventually, we'll move away from implementing SandstormCore\n # in the front-end and have it be implemented in the backend. This method will go away then.\n\n getGatewayRouter @1 () -> (router :GatewayRouter);\n # Gets an GatewayRouter implementation. Note that in Blackrock, where multiple instances of the\n # shell might be running, all GatewayRouters are equivalent, regardless of which shell replica\n # they came from.\n}\n",
"bridge-proxy.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xbf72526e76ecd73b;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\nusing Util = import \"util.capnp\";\n\nstruct ProxyClaimRequestRequest {\n requestToken @0 :Text;\n requiredPermissions @1 :List(Text);\n label @2 :Util.LocalizedText;\n}\n\nstruct ProxyClaimRequestResponse {\n cap @0 :Text;\n}\n",
"email-impl.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This is used specifically with hack-session.capnp.\n# It is subject to change after the Powerbox functionality is implemented.\n\n@0x92829022d203a580;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Email = import \"email.capnp\";\nusing SystemPersistent = import \"supervisor.capnp\".SystemPersistent;\n\ninterface PersistentEmailVerifier extends (Email.EmailVerifier, SystemPersistent) {}\ninterface PersistentVerifiedEmail extends (Email.VerifiedEmail, SystemPersistent) {}\n",
"grain.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xc8d91463cfc4fb4a;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing Powerbox = import \"powerbox.capnp\";\nusing Activity = import \"activity.capnp\";\nusing Identity = import \"identity.capnp\";\n\n# ========================================================================================\n# Runtime interface\n\ninterface SandstormApi(AppObjectId) {\n # The Sandstorm platform API, exposed as the default capability over the two-way RPC connection\n # formed with the application instance. This object specifically represents the supervisor\n # for this application instance -- two different application instances (grains) never share a\n # supervisor.\n #\n # `AppObjectId` is the format in which the application identifies its persistent objects which\n # can be saved from the outside; see `AppPersistent`, below.\n\n # TODO(soon): Read the grain title as set by the user. Also have interface to offer a new\n # title and icon?\n\n deprecatedPublish @0 ();\n deprecatedRegisterAction @1 ();\n # These powerbox-related methods were never implemented. Eventually it was decided that they\n # specified the wrong model.\n\n shareCap @2 (cap :Capability, displayInfo :Powerbox.PowerboxDisplayInfo)\n -> (sharedCap :Capability, link :SharingLink);\n # Share a capability, so that it may safely be sent to another user. `sharedCap` is a wrapper\n # (membrane) around `cap` which can have a petname assigned and can be revoked via `link`. The\n # share is automatically revoked if `link` is discarded. If `cap` is persistable, then both\n # `sharedCap` and `link` also are.\n #\n # This method is intended to be used by programs that actually implement a communications link\n # over which a capability could be sent from one user to another. For example, a chat app would\n # use this to prepare a capability to be embedded into a message. In these cases, capabilities\n # may be shared without going through the system sharing UI, and therefore the application must\n # set up the sharing link itself.\n #\n # In general, you should NOT call this on a capability that you will then pass to\n # `SessionContext.offer()`.\n\n shareView @3 (view :UiView) -> (sharedView :UiView, link :ViewSharingLink);\n # Like `shareCap` but with extra options for sharing a UiView, such as setting a role and\n # permissions.\n\n save @8 (cap :Capability, label :Util.LocalizedText) -> (token :Data);\n # Saves a persistent capability and returns a token which can be used to restore it later\n # (including in a future run of the app) via `restore()` (below). Not all capabilities can be\n # saved -- check the documentation for the capability you are using to see if it is described as\n # \"persistent\".\n #\n # The grain owner will be able to inspect saved capabilities via the UI. `label` will be shown\n # there and should briefly describe what this capability is used for.\n #\n # To see how to make your own app's objects persistent, see the `AppPersistent` interface defined\n # later in this file. Note that it's perfectly valid to pass your app's own capabilities to\n # `save()`, if they are persistent in this way.\n #\n # (Under the hood, `SandstormApi.save()` calls the capability's `AppPersistent.save()` method,\n # then stores the result in a table indexed by the new randomly-generated token. The app CANNOT\n # call `AppPersistent.save()` on external capabilities itself; such calls will be blocked by the\n # supervisor (and the result would be useless to you anyway, because you have no way to restore\n # it). You must use `SandstormApi.save()` so that saved capabilities can be inspected by the\n # user.)\n\n restore @4 (token :Data) -> (cap :Capability);\n # Given a token previously returned by `save()`, get the capability it pointed to. The returned\n # capability should implement the same interfaces as the one you saved originally, so you can\n # downcast it as appropriate.\n\n drop @5 (token :Data);\n # Deletes the token and frees any resources being held with it. Once drop()ed, you can no longer\n # restore() the token. This call is idempotent: it is not an error to `drop()` a token that has\n # already been dropped.\n\n deleted @6 (ref :AppObjectId);\n # Notifies the supervisor that an object hosted by this application has been deleted, and\n # therefore all references to it may as well be dropped. This affects *incoming* references,\n # whereas `drop()` affects *outgoing*.\n\n stayAwake @7 (displayInfo :Activity.NotificationDisplayInfo,\n notification :Activity.OngoingNotification)\n -> (handle :Util.Handle);\n # Requests that the app be allowed to continue running in the background, even if no user has it\n # open in their browser. An ongoing notification is delivered to the user who owns the grain to\n # let them know of this. The user may cancel the notification, in which case the app will no\n # longer be kept awake. If not canceled, the app remains awake at least until it drops `handle`.\n #\n # Unlike other ongoing notifications, `notification` in this case need not be persistent (since\n # the whole point is to prevent the app from restarting), and `handle` is not persistent.\n #\n # WARNING: A machine failure or similar situation can still cause the app to shut down at any\n # time. Currently, the app will NOT be restarted after such a failure.\n #\n # TODO(someday): We could make `handle` be persistent. If the app persists it -- and if\n # `notification` is persistent -- we would automatically restart the app after an unexpected\n # failure.\n\n backgroundActivity @9 (event :Activity.ActivityEvent);\n # Post an activity event to the grain's activity log that was *not* initiated by any particular\n # user. For activity that should be attributed to a user, use SessionContext.activity().\n\n getIdentityId @10 (identity: Identity.Identity) -> (id :Data);\n # Gets the ID of the identity, as it would appear in UserInfo.identityId.\n #\n # This method is here on `SandstormApi` rather than on `Identity` in order to ease a possible\n # future transition to a model where identity IDs are not globally stable and each grain has a\n # separate (possibly incompatible) map from identity ID to account ID.\n}\n\ninterface UiView @0xdbb4d798ea67e2e7 {\n # Implements a user interface with which a user can interact with the grain. We call this a\n # \"view\" because a single grain may actually have multiple \"views\" that provide different\n # functionality or represent multiple logical objects in the same physical grain.\n #\n # When an application starts up, it must export an instance of UiView as its starting\n # capability on the Cap'n Proto two-party connection. This represents the grain's main view and\n # is what the user will see when they open the grain.\n #\n # It is possible for a grain to export additional views via the usual powerbox mechanisms. For\n # instance, a spreadsheet app might let the user create a \"view\" of a few cells of the\n # spreadsheet, allowing them to share those cells to another user without sharing the entire\n # sheet. To accomplish this, the app would create an alternate UiView object that implements\n # an interface just to those cells, and then would use `UiSession.offer()` to offer this object\n # to the user. The user could then choose to open it, share it, save it for later, etc.\n #\n # TODO(apibump): Parameterize UiView on:\n # - A struct type representing permissions, which must have only boolean fields, each annotated\n # with a PermissionDef. Replace all istances of PermissionSet with this.\n # - An enum type representing roles, each annotated with its permission set and a RoleDef.\n # (Requires Cap'n Proto changes to allow parametirizing on enum types, I guess...)\n # - An enum type representing activity event types, each annotated with an ActivityTypeDef.\n\n getViewInfo @0 () -> ViewInfo;\n # Get metadata about the view, especially relating to sharing.\n\n struct ViewInfo {\n permissions @0 :List(PermissionDef);\n # List of permission bits which apply to this view. Permissions typically include things like\n # \"read\" and \"write\". When sharing a view, the sending user may select a set of permissions to\n # grant to the receiving user, and may modify this set later on. When a new user interface\n # session is initiated, the platform indicates which permissions the user currently has.\n #\n # The grain's owner always has all permissions.\n #\n # It is important that new versions of the app only add new permissions, never remove existing\n # ones, since permission IDs are indexes into the list and persist through upgrades.\n #\n # In a true capability system, permissions would normally be implemented by wrapping the main\n # view in filters that prohibit disallowed actions. For example, to give a user read-only\n # access to a grain, you might wrap its UiView in a wrapper that checks all incoming requests\n # and disallows the ones that would modify the content. However, this approach does not work\n # terribly well for UiView for a few reasons:\n #\n # - For complex UIs, HTTP is often the wrong level of abstraction for this kind of filtering.\n # It _may_ work for modern apps that push all UI logic into static client-side Javascript and\n # only serve RPCs over dynamic HTTP, but it won't work well for many legacy apps, and we want\n # to be able to port some of those apps to Sandstorm.\n #\n # - If a UiView is reshared several times, each time adding a new filtering wrapper, then\n # requests could get slow as they have to pass through all the separate filters. This would\n # be especially bad if some of the filters live in other grains, as those grains would have\n # to spin up whenever the resulting view is used.\n #\n # - Compared to computers, humans are relatively less likely to be vulnerable to confused\n # deputy attacks and relatively more likely to be confused by the concept of having multiple\n # capabilities to the same object that provide different access levels. For example, say\n # Alice and Bob both share the same document to Carol, but Alice only grants read access\n # while Bob gives read/write. Carol should only see one instance of the document in her\n # grain list and she should see the read/write interface when she opens it. But this instance\n # isn't simply the one she got from Bob -- if Bob revokes his share but Alice continues to\n # share read rights, Carol should now see the read-only interface when she opens the same\n # grain.\n #\n # To solve all three problems, we have permission bits that are processed when creating a new\n # session. Instead of filtering individual requests, wrappers of UiView only need to filter\n # calls to `newSession()` in order to restrict the permission set as appropriate. Once a\n # session is thus created, it represents a direct link to the target grain. Also, the platform\n # can implement special handling of sharing and permission bits that allow it to recognize when\n # two UiViews are really the same view with different permissions applied, and can then combine\n # them in the UI as appropriate.\n #\n # Implementation-wise, in addition to the permissions enumerated here, there is an additional\n # \"is human\" pseudopermission provided by the Sandstorm platform, which is invisible to apps,\n # but affects how UiView capabilities may be used. In particular, all users are said to possess\n # the \"is human\" pseudopermission, whereas all other ApiTokenOwners do not, and by default, the\n # privilege is not passed on. All method calls on UiView require that the caller have the \"is\n # human\" permission. In practical terms, this means that grains can pass around UiView\n # capabilities, but only users can actually use them to open sessions.\n #\n # It is actually entirely possible to implement a traditional filtering membrane around a\n # UiView, perhaps to implement a kind of access that can't be expressed using the permission\n # bits defined by the app. But doing so will be awkward, slow, and confusing for all the\n # reasons listed above.\n\n roles @1 :List(RoleDef);\n # Choosing individual permissions is not very intuitive for most users. Therefore, the sharing\n # interface prefers to offer the user a list of \"roles\" to assign to each recipient. For\n # example, a document might have roles like \"editor\" and \"viewer\". Each role corresponds to\n # some list of permissions. The application may define a set of roles to offer via this list.\n #\n # In addition to the roles in this list, the sharing interface will always offer a \"full access\"\n # or \"same as me\" option. So, it only makes sense to define roles that represent less than\n # \"full access\", and leaving the role list entirely empty is reasonable if there are no such\n # restrictions to offer.\n #\n # It is important that new versions of the app only add new roles, never remove existing ones,\n # since role IDs are indexes into the list and persist through upgrades.\n\n deniedPermissions @2 :Identity.PermissionSet;\n # Set of permissions which will be removed from the permission set when creating a new session\n # though this object. This set should be empty for the grain's main UiView, but when that view\n # is shared with less than full access, recipients will get a proxy UiView which has a non-empty\n # `deniedPermissions` set.\n #\n # It is not the caller's responsibility to enforce this set. It is provided mainly so that the\n # sharing UI can avoid offering options to the user that don't make sense. For instance, if\n # Alice has read-only access to a document and wishes to share the document to Bob, the sharing\n # UI should not offer Alice the ability to share write access, because she doesn't have it in\n # the first place. The sharing UI figures out what Alice has by examining `deniedPermissions`.\n\n matchRequests @3 :List(Powerbox.PowerboxDescriptor);\n # Indicates what kinds of powerbox requests this grain may be able to fulfill. If the grain\n # is chosen by the user during a powerbox request, then `newRequestSession()` will be called\n # to set up the embedded UI session.\n\n matchOffers @4 :List(Powerbox.PowerboxDescriptor);\n # Indicates what kinds of powerbox offers this grain is interested in accepting. If the grain\n # is chosen by the user during a powerbox offer, then `newOfferSession()` will be called\n # to start a session around this.\n\n appTitle @5 :Util.LocalizedText;\n # Title for the app of which this grain is an instance.\n\n grainIcon @6 :Util.StaticAsset;\n # Icon for the app of which this grain is an instance, suitable for display in a grain list.\n\n eventTypes @7 :List(Activity.ActivityTypeDef);\n # Definitions of activity event types generated by this grain. Each activity event is tagged\n # with one of these types. Typed events potentially allow for advanced filtering options and\n # compact activity summaries.\n }\n\n struct PowerboxTag {\n # Tag to be used in a `PowerboxDescriptor` to describe a `UiView`.\n\n title @0 :Text;\n # The title of the `UiView` as chosen by the introducer identity.\n }\n\n newSession @1 (userInfo :Identity.UserInfo, context :SessionContext,\n sessionType :UInt64, sessionParams :AnyPointer,\n tabId :Data)\n -> (session :UiSession);\n # Start a new user interface session. This happens when a user first opens the view, or when\n # the user returns to a tab that has been inactive long enough that the server was killed off in\n # the meantime.\n #\n # `userInfo` specifies the user's display name and permissions, as authenticated by the system.\n #\n # `context` contains callbacks that can be used to invoke system functionality in the context of\n # the session, such as displaying the powerbox.\n #\n # `sessionType` is the type ID specifying the interface which the returned `session` should\n # implement. All views should support the `WebSession` interface to support opening the view\n # in a browser. Other session types might be useful for e.g. desktop and mobile apps.\n #\n # `sessionParams` is a struct whose type is specified by the session type. By convention, this\n # struct should be defined nested in the session interface type with name \"Params\", e.g.\n # `WebSession.Params`. This struct contains some arbitrary startup information.\n #\n # `tabId` is a stable identifier for the \"tab\" (as in, Sandstorm sidebar tab) in which the grain\n # is being displayed. A single tab may span multiple UiSessions, for instance if the user\n # suspends their laptop and then restores later, or if the grain crashes. More importantly,\n # `tabId` allows multiple grains being composed in the same tab to coordinate. For example, when\n # a grain is embedded in the powerbox UI to respond to a request, it sees the same `tabId` as\n # the requesting grain. Similarly, when a grain embeds other grains within iframes within its\n # own UI, they will all see the same `tabId`. One particular case where `tabId` is useful is\n # in implementing an `EmailVerifier` that cannot be MITM'd. NOTE: `tabId` should NOT be presumed\n # to be a secret, although no two tabs in all of time will have the same `tabId`.\n #\n # For API requests, `tabId` uniquely identifies the token, as so can be used to correlate\n # multiple requests from the same client.\n\n newRequestSession @2 (userInfo :Identity.UserInfo, context :SessionContext,\n sessionType :UInt64, sessionParams :AnyPointer,\n requestInfo :List(Powerbox.PowerboxDescriptor), tabId :Data)\n -> (session :UiSession);\n # Creates a new session based on a powerbox request. `requestInfo` is the subset of the original\n # request description which matched descriptors that this grain indicated it provides via\n # `ViewInfo.matchRequests`. The list is also sorted with the \"best match\" first, such that\n # it is reasonable for a grain to ignore all descriptors other than the first.\n #\n # Keep in mind that, as with any other session, the UiSession capability could become\n # disconnected randomly and the front-end will then reconnect by calling `newRequestSession()`\n # again with the same parameters. Generally, apps should avoid storing any session-related state\n # on the server side; it's easy to use client-side sessionStorage instead.\n #\n # The `tabId` passed here identifies the requesting tab; see docs under `newSession()`.\n\n newOfferSession @3 (userInfo :Identity.UserInfo, context :SessionContext,\n sessionType :UInt64, sessionParams :AnyPointer,\n offer :Capability, descriptor :Powerbox.PowerboxDescriptor,\n tabId :Data)\n -> (session :UiSession);\n # Creates a new session based on a powerbox offer. `offer` is the capability being offered and\n # `descriptor` describes it.\n #\n # By default, an \"offer\" session is displayed embedded in the powerbox much like a \"request\"\n # session is. If the the session implements a quick action -- say \"share to friend by email\" --\n # then it may make sense for it to remain embedded, returning the user to the offering app when\n # done. The app may call `SessionContext.close()` to indicate that it's time to close. However,\n # in some cases it makes a lot of sense for the app to become \"full-frame\", for example a\n # document editor app accepting a document offer may want to then open the editor for long-term\n # use. Such apps should call `SessionContext.openView()` to move on to a full-fledged session.\n # Finally, some apps will take an offer, wrap it in some filter, and then make a new offer of the\n # wrapped capability. To that end, calling `SessionContext.offer()` will end the offer session\n # but immediately start a new offer interaction in its place using the new capability.\n #\n # Keep in mind that, as with any other session, the UiSession capability could become\n # disconnected randomly and the front-end will then reconnect by calling `newOfferSession()`\n # again with the same parameters. Generally, apps should avoid storing any session-related state\n # on the server side; it's easy to use client-side sessionStorage instead. (Of course, if the\n # session calls `SessionContext.openView()`, the new view will be opened as a regular session,\n # not an offer session.)\n #\n # The `tabId` passed here identifies the offering tab; see docs under `newSession()`.\n}\n\n# ========================================================================================\n# User interface sessions\n\ninterface UiSession {\n # Base interface for UI sessions. The most common subclass is `WebSession`.\n}\n\ninterface SessionContext {\n # Interface that the application can use to call back to the platform in the context of a\n # particular session. This can be used e.g. to ask the platform to present certain system\n # dialogs to the user.\n\n getSharedPermissions @0 () -> (var :Util.Assignable(Identity.PermissionSet).Getter);\n # Returns an observer on the permissions held by the user of this session.\n # This observer can be persisted beyond the end of the session. This is useful for detecting if\n # the user later loses their access and auto-revoking things in that case. See also `tieToUser()`\n # for an easier way to make a particular capability auto-revoke if the user's permissions change.\n\n tieToUser @1 (cap :Capability, requiredPermissions :Identity.PermissionSet,\n displayInfo :Powerbox.PowerboxDisplayInfo)\n -> (tiedCap :Capability);\n # Create a version of `cap` which will automatically stop working if the user no longer holds the\n # permissions indicated by `requiredPermissions` (and starts working again if the user regains\n # those permissions). The capability also appears connected to the user in the sharing\n # visualization.\n #\n # Keep in mind that, security-wise, calling this also implies exposing `tiedCap` to the user, as\n # anyone with a UiView capability can always initiate a session and pass in their own\n # `SessionContext`. If you need to auto-revoke a capability based on the user's permissions\n # _without_ actually passing that capability to the user, use `getSharedPermissions()` to detect\n # when the user's permissions change and implement it yourself.\n\n offer @2 (cap :Capability, requiredPermissions :Identity.PermissionSet,\n descriptor :Powerbox.PowerboxDescriptor, displayInfo :Powerbox.PowerboxDisplayInfo);\n # Offer a capability to the user. A dialog box will ask the user what they want to do with it.\n # Depending on the type of capability (as indicated by `descriptor`), different options may be\n # provided. All capabilities will offer the user the option to save the capability to their\n # capability/grain store. Other type-specific actions may be offered by the platform or by other\n # applications.\n #\n # For example, offering a UiView will give the user options like \"open in new tab\", \"save to\n # grain list\", and \"share with another user\".\n #\n # The capability is implicitly tied to the user as if via `tieToUser()`.\n\n request @3 (query :List(Powerbox.PowerboxDescriptor), requiredPermissions :Identity.PermissionSet)\n -> (cap :Capability, descriptor :Powerbox.PowerboxDescriptor);\n # Although this method exists, it is unimplemented and currently you are meant to use the\n # postMessage api to get a temporary token and then restore it with claimRequest().\n #\n # The postMessage api is an rpc interface so you will have to listen for a `message` callback\n # after sending a postMessage. The postMessage object should have the following form:\n #\n # powerboxRequest:\n # rpcId: A unique string that should identify this rpc message to the app. You will receive this\n # id in the callback to verify which message it is referring to.\n # query: A list of PowerboxDescriptor objects, serialized as a Javascript array of\n # base64-encoded packed powerbox query descriptors created using the `spk query` tool.\n # saveLabel: A petname to give this label. This will be displayed to the user as the name\n # for this capability.\n #\n # e.g.:\n # window.parent.postMessage({\n # powerboxRequest: {\n # rpcId: myRpcId,\n # query: [\n # // encoded/packed/base64url of (tags = [(id = 15831515641881813735)])\n # \"EAZQAQEAABEBF1EEAQH_5-Jn6pjXtNsAAAA\",\n # ],\n # saveLabel: { defaultText: \"Linked grain\" },\n # },\n # }, \"*\");\n #\n # The postMessage searches for capabilities in the user's powerbox matching the given query and\n # displays a selection UI to the user.\n # This will then initiate a powerbox interaction with the user, and when it is done, a postMessage\n # callback to the grain will occur. You can listen for such a message like so:\n # window.addEventListener(\"message\", function (event) {\n # if (event.data.rpcId === myRpcId && !event.data.error) {\n # // Pass `event.data.token` to your app's server and call SessionContext.claimRequest() with\n # // it. The token is guaranteed to be a URL-safe string. That is, passing it through\n # // encodeURIComponent() should be a no-op.\n # }\n # }, false)\n\n claimRequest @7 (requestToken :Text, requiredPermissions :Identity.PermissionSet)\n -> (cap :Capability);\n # When a powerbox request is initiated client-side via the postMessage API and the user completes\n # the request flow, the Sandstorm shell responds to the requesting app with a token. This token\n # itself is not a SturdyRef, but can be exchanged server-side for a capability which in turn\n # can be save()d to produce a SturdyRef. `claimRequest()` is the method to call to exchange the\n # token for a capability. It must be called within a short period after the powerbox request\n # completes; we recommend that the app immediately send the token up to its server to claim\n # the capability.\n #\n # If you are familiar with OAuth, the `requestToken` can be compared to an OAuth \"authorization\n # code\", whereas a SturdyRef is like an \"access token\". The authorization code must be exchanged\n # for an access token in a server-to-server interaction.\n #\n # You might consider an alternative approach in which the client-side response includes a\n # newly-minted SturdyRef directly, avoiding the need for a server-side exchange. The problem with\n # that approach is that it makes SturdyRef leaks more dangerous. If an application leaks one of\n # its SturdyRefs to an attacker, the attacker may then initiate a powerbox request on the client\n # side in which the attacker spoofs the response from the Sandstorm shell to inject the leaked\n # SturdyRef. The app likely will not realize that this SturdyRef was not newly-minted and may\n # then use it in a context where it was not intended. Adding the claimRequest() requirement makes\n # a leaked SturdyRef less likely to be useful to an attacker since the attacker cannot usefully\n # inject the SturdyRef into a subsequent spoofed powerbox response, since a SturdyRef is not\n # usable as a `requestToken`.\n #\n # `requiredPermissions` specifies permissions which must be held on *this* grain by the user\n # who completed the powerbox interaction. (The implicit \"can access the grain at all\" permission\n # is always treated as a required permission, even if `requiredPermissions` is null or empty.)\n # This way, if a user of a grain connects the grain to other resources, but later has their access\n # to the grain revoked, these connections are revoked as well.\n #\n # Consider this example: Alice owns a grain which implements a discussion forum. At some point,\n # Alice invites Dave to participate in the forum, and she gives him moderator permissions. As\n # part of being a moderator, Dave arranges to have a notification emailed to him whenever a post\n # is flagged for moderation. To set this up, the forum app makes a powerbox request for an email\n # send capability directed to his email address. Later on, Alice decides to demote Dave from\n # \"moderator\" status to \"participant\". At this point, Dave should stop receiving email\n # notifications; the capability he introduced in the powerbox request should be revoked. Alice\n # actually has no idea that Dave set up to receive these notifications, so she does not know\n # to revoke it manually; we want it to happen automatically, or at least we want to be able to\n # call Alice's attention to it.\n #\n # To this end, after the Powerbox request is made through Dave and he chooses a capability, the\n # app will call `claimRequest()` and indicate in `requiredPermissions` that Dave must have\n # \"moderator\" permission. The app then `save()`s the capability. In the future, if Dave has lost\n # this permission, then attempts to `restore()` the SturdyRef will fail.\n\n fulfillRequest @4 (cap :Capability, requiredPermissions :Identity.PermissionSet,\n descriptor :Powerbox.PowerboxDescriptor, displayInfo :Powerbox.PowerboxDisplayInfo);\n # For sessions started with `newRequestSession()`, fulfills the original request. If only one\n # capability was requested, the powerbox will close upon `fulfillRequest()` being called. If\n # multiple capabilities were requested, then the powerbox remains open and `fulfillRequest()` may\n # be called repeatedly.\n #\n # If the session was not started with `newRequestSession()`, this method is equivalent to\n # `offer()`. This can be helpful when building a UI that can be used both embedded in the\n # powerbox and stand-alone.\n\n close @5 ();\n # Closes the session.\n # - For regular sessions, the user will be returned to the home screen.\n # - For powerbox \"request\" sessions, the user will be returned to the main grain selection list.\n # - For powerbox \"offer\" sessions, the powerbox will be closed and the user will return to the\n # offering app.\n #\n # Note that in some cases it is possible for the user to return by clicking \"back\", so the app\n # should not assume that no further requests will happen.\n\n openView @6 (view :UiView, path :Text = \"\", newTab :Bool = false);\n # Navigates the user to some other UiView (from the same grain or another), closing the current\n # session. If `view` is null, navigates back to the the current view, in a new session.\n #\n # `path` is an optional path to jump directly to within the new session. For WebSessions, this\n # is appended to the URL, and may include query (search) and fragment (hash) components, but\n # should never start with '/'. Example: \"foo/bar?baz=qux#corge\"\n #\n # If `newTab` is true, the new session is opened in a new tab.\n #\n # If the current session is a powerbox session, `openView()` affects the top-level tab, thereby\n # closing the powerbox and the app that initiated the powerbox (unless `newTab` is true).\n\n activity @8 (event :Activity.ActivityEvent);\n # Call each time the user performs some activity that should be logged.\n}\n\n# ========================================================================================\n# Sharing and Access Control\n\nstruct PermissionDef {\n # Metadata describing a permission bit.\n\n name @3 :Text;\n # Name of the permission, used as an identifier for the permission in cases where string names\n # are preferred. These names will never be used in Cap'n Proto interfaces, but could show up in\n # HTTP or JSON translations, such as in sandstorm-http-bridge's X-Sandstorm-Permissions header.\n #\n # The name must be a valid identifier (alphanumerics only, starting with a letter) and must be\n # unique among all permissions defined for a particular UiView.\n\n title @0 :Util.LocalizedText;\n # Display name of the permission, e.g. to display in a checklist of permissions that may be\n # assigned when sharing.\n\n description @1 :Util.LocalizedText;\n # Prose describing what this permission means, suitable for a tool tip or similar help text.\n\n obsolete @2 :Bool = false;\n # If true, this permission was relevant in a previous version of the application but should no\n # longer be offered to the user in future sharing actions.\n}\n\nstruct RoleDef {\n # Metadata describing a shareable role.\n\n title @0 :Util.LocalizedText;\n # Name of the role, e.g. \"editor\" or \"viewer\".\n\n verbPhrase @1 :Util.LocalizedText;\n # Verb phrase describing what users in this role can do with the grain. Should be something\n # like \"can edit\" or \"can view\". When the user shares the view with others, these verb phrases\n # will be used to populate a drop-list of roles for the user to select.\n\n description @2 :Util.LocalizedText;\n # Prose describing what this role means, suitable for a tool tip or similar help text.\n\n permissions @3 :Identity.PermissionSet;\n # Permissions which make up this role. For example, the \"editor\" role on a document would\n # typically include \"read\" and \"write\" permissions.\n\n obsolete @4 :Bool = false;\n # If true, this role was relevant in a previous version of the application but should no longer\n # be offered to the user in future sharing actions. The role may still be displayed if it was\n # used to share the view while still running the old version.\n\n default @5 :Bool = false;\n # If true, this role should be used for any sharing actions that took place using a previous\n # version of the app that did not define any roles. This allows you to seamlessly add roles to\n # an already-deployed app without breaking existing shares. If you do not mark any roles as\n # \"default\", then such sharing actions will be treated as having an empty permissions set (the\n # user can open the grain, but the grain is told that the user has no permissions).\n #\n # See also `ViewSharingLink.RoleAssignment.none`, below.\n}\n\ninterface SharingLink {\n # Represents one link in the sharing graph.\n\n getPetname @0 () -> (name :Util.Assignable(Util.LocalizedText));\n # Name assigned by the sharer to the recipient.\n}\n\ninterface ViewSharingLink extends(SharingLink) {\n # A SharingLink for a UiView. These links can be attenuated with permissions.\n\n getRoleAssignment @0 () -> (var :Util.Assignable(RoleAssignment));\n # Returns an Assignable containing a RoleAssignment.\n\n struct RoleAssignment {\n union {\n none @0: Void;\n # No role was explicitly chosen. The main case where this happens is when an app defining\n # no roles is shared. Note that \"none\" means \"no role\", but does NOT necessarily mean\n # \"no permissions\". If a default role is defined (see `RoleDef.default`), that will be used.\n\n allAccess @1 :Void; # Grant all permissions.\n roleId @2 :UInt16; # Grant permissions for the given role.\n }\n\n addPermissions @3 :Identity.PermissionSet;\n # Permissions to add on top of those granted above.\n\n removePermissions @4 :Identity.PermissionSet;\n # Permissions to remove from those granted above.\n }\n}\n\n# ========================================================================================\n# Backup and Restore\n\nstruct GrainInfo {\n # Format of metadata file stored in grain backups.\n\n appId @0 :Text;\n appVersion @1 :UInt32;\n title @2 :Text;\n\n ownerIdentityId @3 :Text;\n\n # TODO(someday): Record the whole sharing / capability graph including all users' identity IDs\n # so that they can be restored.\n}\n\n# ========================================================================================\n# Persistent objects\n\ninterface AppPersistent @0xaffa789add8747b8 (AppObjectId) {\n # To make an object implemented by your own app persistent, implement this interface.\n #\n # `AppObjectId` is a structure like a URL which identifies a specific object within your app.\n # You may define this structure any way you want. For example, it could literally be a string\n # URL, or it could be a database ID, or it could actually be a serialized representation of an\n # object that isn't actually stored anywhere (like a \"data URL\").\n #\n # Other apps and external clients will never actually see your `AppObjectId`; it is stored by\n # Sandstorm itself, and clients only see an opaque token. Therefore, you need not encrypt, sign,\n # authenticate, or obfuscate this structure. Moreover, Sandstorm will ensure that only clients\n # who previously saved the object are able to restore it.\n #\n # Note: This interface is called `AppPersistent` rather than just `Persistent` to distinguish it\n # from Cap'n Proto's `Persistent` interface, which is a more general (and more confusing)\n # version of this concept. Many things that the general Cap'n Proto `Persistent` must deal\n # with are handled by Sandstorm, so Sandstorm apps need not think about them. Cap'n Proto\n # also uses the term `SturdyRef` rather than `ObjectId` -- the major difference is that\n # `SturdyRef` is cryptographically secure whereas `ObjectId` need not be because it is\n # protected by the platform.\n #\n # TODO(cleanup): Consider eliminating Cap'n Proto's `Persistent` interface in favor of having\n # every realm define their own interface. Might actually be less confusing.\n\n save @0 () -> (objectId :AppObjectId, label :Util.LocalizedText);\n # Saves the capability to disk (if it isn't there already) and then returns the object ID which\n # can be passed to `MainView.restore()` to restore it later.\n #\n # The grain owner will be able to inspect externally-held capabilities via the UI. `label` will\n # be shown there and should briefly describe what this capability represents.\n #\n # Note that Sandstorm compares all object IDs your app produces for equality (using Cap'n Proto\n # canonicalization rules) so that it can recognize when the same object is saved multiple times.\n # `MainView.drop()` will be called when all such references have been dropped by their respective\n # clients.\n #\n # TODO(cleanup): How does `label` here relate to `PowerboxDisplayInfo` on `offer()` and\n # `fulfillRequest()`? Maybe `label` here should actually be `PowerboxDisplayInfo` and those\n # other methods shouldn't take that parameter?\n}\n\ninterface MainView(AppObjectId) extends(UiView) {\n # The default (bootstrap) interface exported by a grain to the supervisor when it comes up is\n # actually `MainView`. Only the Supervisor sees this interface. It proxies the `UiView` subset\n # of the interface to the rest of the world, and automatically makes that capability persistent,\n # so that a simple app can completely avoid implementing persistence.\n #\n # `AppObjectId` is a structure type defined by the app which identifies persistent objects\n # within the app, like a URL. See `AppPersistent`, above.\n\n restore @0 (objectId :AppObjectId) -> (cap :Capability);\n # Restore a live object corresponding to an `AppObjectId`. See `AppPersistent`, above.\n #\n # Apps only need to implement this if they publish persistent capabilities (not including the\n # main UiView).\n\n drop @1 (objectId :AppObjectId);\n # Indicates that all external persistent references to the given persistent object have been\n # dropped. Depending on the nature of the underlying object, the app may wish to delete it at\n # this point.\n #\n # Note that this method is unreliable. Drop notifications rely on cooperation from the client,\n # who has to explicitly call `drop()` on their end when they discard the reference. Buggy clients\n # may forget to do this. Clients that are destroyed in a fire may have no opportunity to do this.\n # (This differs from live capabilities, which are tied to an ephemeral connection and implicitly\n # dropped when that connection is closed.)\n #\n # That said, Sandstorm gives the grain owner the ability to inspect incoming refs and revoke them\n # explicitly. If all refs to this object are revoked, then Sandstorm will call `drop()`.\n #\n # In some rare cases, `drop()` may be called more than once on the same object. The app should\n # make sure `drop()` is idempotent.\n}\n",
"identity.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xc822108a5c3d7d25;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\n\nusing PermissionSet = List(Bool);\n# Set of permission IDs, represented as a bitfield.\n\ninterface Identity @0xc084987aa951dd18 {\n # Represents a user identity.\n #\n # Things you can do:\n # - Mention the identity on activity events to send notifications. See ActivityEvent in\n # activity.capnp.\n # - Powerbox-request an Identity to have the user choose from among their contacts. Note that the\n # user will be prompted to share the grain with the target identity.\n # - offer() the identity to the user in order to let them see the identity's profile card and\n # choose to add the identity to their contacts. You could do this e.g. when the user clicks\n # on the identity's name in your app's UI. (TODO(someday): Not implemented yet.)\n #\n # This capability is always persistable.\n\n # TODO(someday): Public key info? Ability to seal messages / check signatures?\n\n struct PowerboxTag {\n # Tag to be used in a `PowerboxDescriptor` to describe an `Identity`.\n\n permissions @0 :PermissionSet;\n # In a query, the permissions that the requester wishes to be held by the identity. When\n # the powerbox UI asks the user to select a role, it hides any roles that do not provide all of\n # these permissions.\n #\n # In a fulfillment, the current permissions actually held by the identity.\n }\n\n getProfile @0 () -> (profile: Profile);\n # Get the identity's current profile.\n}\n\nstruct Profile @0xd3d0c34d7201fcef {\n # Personal information provided by a user, intended to be displayed to other users when\n # they come in contact.\n\n displayName @0 :Util.LocalizedText;\n # Name by which to identify this user within the user interface. For example, if two users are\n # editing a document simultaneously, the application may display each user's cursor position to\n # the other, labeled with the respective display names. As the users edit the document, the\n # document's history may be annotated with the display name of the user who made each change.\n # Display names are NOT unique nor stable: two users could potentially have the same display\n # name and a user's display name could change.\n\n preferredHandle @1 :Text;\n # The user's preferred \"handle\", as set in their account settings. This is guaranteed to be\n # composed only of lowercase English letters, digits, and underscores, and will not start with\n # a digit. It is NOT guaranteed to be unique; if your app dislikes duplicate handles, it must\n # check for them and do something about them.\n\n picture @2 :Util.StaticAsset;\n # The user's profile picture, appropriate for displaying in a 64x64 context.\n\n enum Pronouns {\n neutral @0; # \"they\"\n male @1; # \"he\" / \"him\"\n female @2; # \"she\" / \"her\"\n robot @3; # \"it\"\n }\n\n pronouns @3 :Pronouns;\n # Indicates which pronouns the user prefers you use to refer to them.\n}\n\nstruct UserInfo @0x94b9d1efb35d11d3 {\n # Information about the user opening a new session, including a snapshot of the user's\n # profile.\n #\n # TODO(soon): More details:\n # - Sharing/authority chain: \"Carol (via Bob, via Alice)\"\n\n displayName @0 :Util.LocalizedText;\n # The current value of `identity.getProfile().displayName`, provided here for convenience.\n\n preferredHandle @4 :Text;\n # The current value of `identity.getProfile().preferredHandle`, provided here for convenience.\n\n pictureUrl @6 :Text;\n # The current value of `identity.getProfile().staticAsset.getUrl()`, provided here for\n # convenience.\n #\n # TODO(security) TODO(apibump): If we allow UserInfo to come from untrusted sources then this\n # field is XSS-prone. Currently UserInfo only comes from the front-end.\n\n pronouns @5 :Profile.Pronouns;\n # The current value of `identity.getProfile().pronouns`, provided here for convenience.\n\n deprecatedPermissionsBlob @1 :Data;\n permissions @3 :PermissionSet;\n # Set of permissions which this user has. The exact set might not correspond directly to any\n # particular role for a number of reasons:\n # - The sharer may have toggled individual permissions through the advanced settings.\n # - If two different users share different roles to a third user, and neither of the roles is a\n # strict superset of the other, the user gets the union of the two permissions.\n # - If Alice shares role A to Bob, and Bob further delegates role B to Carol, then Carol's\n # permissions are the intersection of those granted by roles A and B.\n #\n # That said, some combinations of permissions may not make sense. For example, a document editor\n # probably has no reasonable way to implement write permission without read permission. It is up\n # to the application to decide what to do in this case, but simply ignoring the nonsensical\n # permissions is often a fine strategy.\n #\n # If the user's permissions are reduced while the session is opened, the session will be closed\n # by the platform and the user forced to start a new one. If the user's permissions are increased\n # while the session is opened, the system will prompt them to start a new session to use the new\n # permissions. Either way, the application need not worry about permissions changing during a\n # session.\n\n identityId @2 :Data;\n # A unique, stable identifier for the calling user. This is computed such that a user's ID will\n # be the same across all Sandstorm servers, and will not collide with any other identity ID in the\n # world. Therefore, grains transferred between servers can still count on the user IDs being the\n # same and secure (unless the new host is itself malicious, of course, in which case all bets are\n # off).\n #\n # The ID is actually a SHA-256 hash, therefore it is always exactly 32 bytes and the app can\n # safely truncate it down to some shorter prefix according to its own security/storage trade-off\n # needs.\n #\n # If the user is not logged in, `identityId` is null.\n\n identity @7 :Identity;\n # The identity capability for this user. null if the user is not logged in.\n}\n",
"mime.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2018 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0x9dc702ea30180791;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nstruct MimeTypeInfo {\n name @0 :Text;\n extensions @1 :List(Text);\n}\n\n# Generated by:\n#\n# const fetch = require(\"node-fetch\");\n#\n# const p1 = fetch(\"https://raw.githubusercontent.com/broofa/node-mime/master/types/standard.json\")\n# .then(resp => resp.json());\n# const p2 = fetch(\"https://raw.githubusercontent.com/broofa/node-mime/master/types/other.json\")\n# .then(resp => resp.json());\n#\n# function printTypes(map) {\n# for (name in map) {\n# let exts = map[name].join('\",\"');\n# console.log(`(name = \"${name}\", extensions = [\"${exts}\"]),`);\n# }\n# }\n#\n# Promise.all([p1, p2]).then(resps => {\n# printTypes(resps[0]);\n# printTypes(resps[1]);\n# }).catch(err => {\n# console.error(err.stack);\n# });\n\nconst mimeTypeInfoTable :List(MimeTypeInfo) = [\n (name = \"application/andrew-inset\", extensions = [\"ez\"]),\n (name = \"application/applixware\", extensions = [\"aw\"]),\n (name = \"application/atom+xml\", extensions = [\"atom\"]),\n (name = \"application/atomcat+xml\", extensions = [\"atomcat\"]),\n (name = \"application/atomsvc+xml\", extensions = [\"atomsvc\"]),\n (name = \"application/bdoc\", extensions = [\"bdoc\"]),\n (name = \"application/ccxml+xml\", extensions = [\"ccxml\"]),\n (name = \"application/cdmi-capability\", extensions = [\"cdmia\"]),\n (name = \"application/cdmi-container\", extensions = [\"cdmic\"]),\n (name = \"application/cdmi-domain\", extensions = [\"cdmid\"]),\n (name = \"application/cdmi-object\", extensions = [\"cdmio\"]),\n (name = \"application/cdmi-queue\", extensions = [\"cdmiq\"]),\n (name = \"application/cu-seeme\", extensions = [\"cu\"]),\n (name = \"application/dash+xml\", extensions = [\"mpd\"]),\n (name = \"application/davmount+xml\", extensions = [\"davmount\"]),\n (name = \"application/docbook+xml\", extensions = [\"dbk\"]),\n (name = \"application/dssc+der\", extensions = [\"dssc\"]),\n (name = \"application/dssc+xml\", extensions = [\"xdssc\"]),\n (name = \"application/ecmascript\", extensions = [\"ecma\"]),\n (name = \"application/emma+xml\", extensions = [\"emma\"]),\n (name = \"application/epub+zip\", extensions = [\"epub\"]),\n (name = \"application/exi\", extensions = [\"exi\"]),\n (name = \"application/font-tdpfr\", extensions = [\"pfr\"]),\n (name = \"application/font-woff\", extensions = [\"woff\"]),\n (name = \"application/font-woff2\", extensions = [\"*woff2\"]),\n (name = \"application/geo+json\", extensions = [\"geojson\"]),\n (name = \"application/gml+xml\", extensions = [\"gml\"]),\n (name = \"application/gpx+xml\", extensions = [\"gpx\"]),\n (name = \"application/gxf\", extensions = [\"gxf\"]),\n (name = \"application/gzip\", extensions = [\"gz\"]),\n (name = \"application/hjson\", extensions = [\"hjson\"]),\n (name = \"application/hyperstudio\", extensions = [\"stk\"]),\n (name = \"application/inkml+xml\", extensions = [\"ink\",\"inkml\"]),\n (name = \"application/ipfix\", extensions = [\"ipfix\"]),\n (name = \"application/java-archive\", extensions = [\"jar\",\"war\",\"ear\"]),\n (name = \"application/java-serialized-object\", extensions = [\"ser\"]),\n (name = \"application/java-vm\", extensions = [\"class\"]),\n (name = \"application/javascript\", extensions = [\"js\",\"mjs\"]),\n (name = \"application/json\", extensions = [\"json\",\"map\"]),\n (name = \"application/json5\", extensions = [\"json5\"]),\n (name = \"application/jsonml+json\", extensions = [\"jsonml\"]),\n (name = \"application/ld+json\", extensions = [\"jsonld\"]),\n (name = \"application/lost+xml\", extensions = [\"lostxml\"]),\n (name = \"application/mac-binhex40\", extensions = [\"hqx\"]),\n (name = \"application/mac-compactpro\", extensions = [\"cpt\"]),\n (name = \"application/mads+xml\", extensions = [\"mads\"]),\n (name = \"application/manifest+json\", extensions = [\"webmanifest\"]),\n (name = \"application/marc\", extensions = [\"mrc\"]),\n (name = \"application/marcxml+xml\", extensions = [\"mrcx\"]),\n (name = \"application/mathematica\", extensions = [\"ma\",\"nb\",\"mb\"]),\n (name = \"application/mathml+xml\", extensions = [\"mathml\"]),\n (name = \"application/mbox\", extensions = [\"mbox\"]),\n (name = \"application/mediaservercontrol+xml\", extensions = [\"mscml\"]),\n (name = \"application/metalink+xml\", extensions = [\"metalink\"]),\n (name = \"application/metalink4+xml\", extensions = [\"meta4\"]),\n (name = \"application/mets+xml\", extensions = [\"mets\"]),\n (name = \"application/mods+xml\", extensions = [\"mods\"]),\n (name = \"application/mp21\", extensions = [\"m21\",\"mp21\"]),\n (name = \"application/mp4\", extensions = [\"mp4s\",\"m4p\"]),\n (name = \"application/msword\", extensions = [\"doc\",\"dot\"]),\n (name = \"application/mxf\", extensions = [\"mxf\"]),\n (name = \"application/octet-stream\", extensions = [\"bin\",\"dms\",\"lrf\",\"mar\",\"so\",\"dist\",\"distz\",\"pkg\",\"bpk\",\"dump\",\"elc\",\"deploy\",\"exe\",\"dll\",\"deb\",\"dmg\",\"iso\",\"img\",\"msi\",\"msp\",\"msm\",\"buffer\"]),\n (name = \"application/oda\", extensions = [\"oda\"]),\n (name = \"application/oebps-package+xml\", extensions = [\"opf\"]),\n (name = \"application/ogg\", extensions = [\"ogx\"]),\n (name = \"application/omdoc+xml\", extensions = [\"omdoc\"]),\n (name = \"application/onenote\", extensions = [\"onetoc\",\"onetoc2\",\"onetmp\",\"onepkg\"]),\n (name = \"application/oxps\", extensions = [\"oxps\"]),\n (name = \"application/patch-ops-error+xml\", extensions = [\"xer\"]),\n (name = \"application/pdf\", extensions = [\"pdf\"]),\n (name = \"application/pgp-encrypted\", extensions = [\"pgp\"]),\n (name = \"application/pgp-signature\", extensions = [\"asc\",\"sig\"]),\n (name = \"application/pics-rules\", extensions = [\"prf\"]),\n (name = \"application/pkcs10\", extensions = [\"p10\"]),\n (name = \"application/pkcs7-mime\", extensions = [\"p7m\",\"p7c\"]),\n (name = \"application/pkcs7-signature\", extensions = [\"p7s\"]),\n (name = \"application/pkcs8\", extensions = [\"p8\"]),\n (name = \"application/pkix-attr-cert\", extensions = [\"ac\"]),\n (name = \"application/pkix-cert\", extensions = [\"cer\"]),\n (name = \"application/pkix-crl\", extensions = [\"crl\"]),\n (name = \"application/pkix-pkipath\", extensions = [\"pkipath\"]),\n (name = \"application/pkixcmp\", extensions = [\"pki\"]),\n (name = \"application/pls+xml\", extensions = [\"pls\"]),\n (name = \"application/postscript\", extensions = [\"ai\",\"eps\",\"ps\"]),\n (name = \"application/pskc+xml\", extensions = [\"pskcxml\"]),\n (name = \"application/raml+yaml\", extensions = [\"raml\"]),\n (name = \"application/rdf+xml\", extensions = [\"rdf\"]),\n (name = \"application/reginfo+xml\", extensions = [\"rif\"]),\n (name = \"application/relax-ng-compact-syntax\", extensions = [\"rnc\"]),\n (name = \"application/resource-lists+xml\", extensions = [\"rl\"]),\n (name = \"application/resource-lists-diff+xml\", extensions = [\"rld\"]),\n (name = \"application/rls-services+xml\", extensions = [\"rs\"]),\n (name = \"application/rpki-ghostbusters\", extensions = [\"gbr\"]),\n (name = \"application/rpki-manifest\", extensions = [\"mft\"]),\n (name = \"application/rpki-roa\", extensions = [\"roa\"]),\n (name = \"application/rsd+xml\", extensions = [\"rsd\"]),\n (name = \"application/rss+xml\", extensions = [\"rss\"]),\n (name = \"application/rtf\", extensions = [\"rtf\"]),\n (name = \"application/sbml+xml\", extensions = [\"sbml\"]),\n (name = \"application/scvp-cv-request\", extensions = [\"scq\"]),\n (name = \"application/scvp-cv-response\", extensions = [\"scs\"]),\n (name = \"application/scvp-vp-request\", extensions = [\"spq\"]),\n (name = \"application/scvp-vp-response\", extensions = [\"spp\"]),\n (name = \"application/sdp\", extensions = [\"sdp\"]),\n (name = \"application/set-payment-initiation\", extensions = [\"setpay\"]),\n (name = \"application/set-registration-initiation\", extensions = [\"setreg\"]),\n (name = \"application/shf+xml\", extensions = [\"shf\"]),\n (name = \"application/smil+xml\", extensions = [\"smi\",\"smil\"]),\n (name = \"application/sparql-query\", extensions = [\"rq\"]),\n (name = \"application/sparql-results+xml\", extensions = [\"srx\"]),\n (name = \"application/srgs\", extensions = [\"gram\"]),\n (name = \"application/srgs+xml\", extensions = [\"grxml\"]),\n (name = \"application/sru+xml\", extensions = [\"sru\"]),\n (name = \"application/ssdl+xml\", extensions = [\"ssdl\"]),\n (name = \"application/ssml+xml\", extensions = [\"ssml\"]),\n (name = \"application/tei+xml\", extensions = [\"tei\",\"teicorpus\"]),\n (name = \"application/thraud+xml\", extensions = [\"tfi\"]),\n (name = \"application/timestamped-data\", extensions = [\"tsd\"]),\n (name = \"application/voicexml+xml\", extensions = [\"vxml\"]),\n (name = \"application/wasm\", extensions = [\"wasm\"]),\n (name = \"application/widget\", extensions = [\"wgt\"]),\n (name = \"application/winhlp\", extensions = [\"hlp\"]),\n (name = \"application/wsdl+xml\", extensions = [\"wsdl\"]),\n (name = \"application/wspolicy+xml\", extensions = [\"wspolicy\"]),\n (name = \"application/xaml+xml\", extensions = [\"xaml\"]),\n (name = \"application/xcap-diff+xml\", extensions = [\"xdf\"]),\n (name = \"application/xenc+xml\", extensions = [\"xenc\"]),\n (name = \"application/xhtml+xml\", extensions = [\"xhtml\",\"xht\"]),\n (name = \"application/xml\", extensions = [\"xml\",\"xsl\",\"xsd\",\"rng\"]),\n (name = \"application/xml-dtd\", extensions = [\"dtd\"]),\n (name = \"application/xop+xml\", extensions = [\"xop\"]),\n (name = \"application/xproc+xml\", extensions = [\"xpl\"]),\n (name = \"application/xslt+xml\", extensions = [\"xslt\"]),\n (name = \"application/xspf+xml\", extensions = [\"xspf\"]),\n (name = \"application/xv+xml\", extensions = [\"mxml\",\"xhvml\",\"xvml\",\"xvm\"]),\n (name = \"application/yang\", extensions = [\"yang\"]),\n (name = \"application/yin+xml\", extensions = [\"yin\"]),\n (name = \"application/zip\", extensions = [\"zip\"]),\n (name = \"audio/3gpp\", extensions = [\"*3gpp\"]),\n (name = \"audio/adpcm\", extensions = [\"adp\"]),\n (name = \"audio/basic\", extensions = [\"au\",\"snd\"]),\n (name = \"audio/midi\", extensions = [\"mid\",\"midi\",\"kar\",\"rmi\"]),\n (name = \"audio/mp3\", extensions = [\"*mp3\"]),\n (name = \"audio/mp4\", extensions = [\"m4a\",\"mp4a\"]),\n (name = \"audio/mpeg\", extensions = [\"mpga\",\"mp2\",\"mp2a\",\"mp3\",\"m2a\",\"m3a\"]),\n (name = \"audio/ogg\", extensions = [\"oga\",\"ogg\",\"spx\"]),\n (name = \"audio/s3m\", extensions = [\"s3m\"]),\n (name = \"audio/silk\", extensions = [\"sil\"]),\n (name = \"audio/wav\", extensions = [\"wav\"]),\n (name = \"audio/wave\", extensions = [\"*wav\"]),\n (name = \"audio/webm\", extensions = [\"weba\"]),\n (name = \"audio/xm\", extensions = [\"xm\"]),\n (name = \"font/collection\", extensions = [\"ttc\"]),\n (name = \"font/otf\", extensions = [\"otf\"]),\n (name = \"font/ttf\", extensions = [\"ttf\"]),\n (name = \"font/woff\", extensions = [\"*woff\"]),\n (name = \"font/woff2\", extensions = [\"woff2\"]),\n (name = \"image/apng\", extensions = [\"apng\"]),\n (name = \"image/bmp\", extensions = [\"bmp\"]),\n (name = \"image/cgm\", extensions = [\"cgm\"]),\n (name = \"image/g3fax\", extensions = [\"g3\"]),\n (name = \"image/gif\", extensions = [\"gif\"]),\n (name = \"image/ief\", extensions = [\"ief\"]),\n (name = \"image/jp2\", extensions = [\"jp2\",\"jpg2\"]),\n (name = \"image/jpeg\", extensions = [\"jpeg\",\"jpg\",\"jpe\"]),\n (name = \"image/jpm\", extensions = [\"jpm\"]),\n (name = \"image/jpx\", extensions = [\"jpx\",\"jpf\"]),\n (name = \"image/ktx\", extensions = [\"ktx\"]),\n (name = \"image/png\", extensions = [\"png\"]),\n (name = \"image/sgi\", extensions = [\"sgi\"]),\n (name = \"image/svg+xml\", extensions = [\"svg\",\"svgz\"]),\n (name = \"image/tiff\", extensions = [\"tiff\",\"tif\"]),\n (name = \"image/webp\", extensions = [\"webp\"]),\n (name = \"message/rfc822\", extensions = [\"eml\",\"mime\"]),\n (name = \"model/gltf+json\", extensions = [\"gltf\"]),\n (name = \"model/gltf-binary\", extensions = [\"glb\"]),\n (name = \"model/iges\", extensions = [\"igs\",\"iges\"]),\n (name = \"model/mesh\", extensions = [\"msh\",\"mesh\",\"silo\"]),\n (name = \"model/vrml\", extensions = [\"wrl\",\"vrml\"]),\n (name = \"model/x3d+binary\", extensions = [\"x3db\",\"x3dbz\"]),\n (name = \"model/x3d+vrml\", extensions = [\"x3dv\",\"x3dvz\"]),\n (name = \"model/x3d+xml\", extensions = [\"x3d\",\"x3dz\"]),\n (name = \"text/cache-manifest\", extensions = [\"appcache\",\"manifest\"]),\n (name = \"text/calendar\", extensions = [\"ics\",\"ifb\"]),\n (name = \"text/coffeescript\", extensions = [\"coffee\",\"litcoffee\"]),\n (name = \"text/css\", extensions = [\"css\"]),\n (name = \"text/csv\", extensions = [\"csv\"]),\n (name = \"text/html\", extensions = [\"html\",\"htm\",\"shtml\"]),\n (name = \"text/jade\", extensions = [\"jade\"]),\n (name = \"text/jsx\", extensions = [\"jsx\"]),\n (name = \"text/less\", extensions = [\"less\"]),\n (name = \"text/markdown\", extensions = [\"markdown\",\"md\"]),\n (name = \"text/mathml\", extensions = [\"mml\"]),\n (name = \"text/n3\", extensions = [\"n3\"]),\n (name = \"text/plain\", extensions = [\"txt\",\"text\",\"conf\",\"def\",\"list\",\"log\",\"in\",\"ini\"]),\n (name = \"text/richtext\", extensions = [\"rtx\"]),\n (name = \"text/rtf\", extensions = [\"*rtf\"]),\n (name = \"text/sgml\", extensions = [\"sgml\",\"sgm\"]),\n (name = \"text/shex\", extensions = [\"shex\"]),\n (name = \"text/slim\", extensions = [\"slim\",\"slm\"]),\n (name = \"text/stylus\", extensions = [\"stylus\",\"styl\"]),\n (name = \"text/tab-separated-values\", extensions = [\"tsv\"]),\n (name = \"text/troff\", extensions = [\"t\",\"tr\",\"roff\",\"man\",\"me\",\"ms\"]),\n (name = \"text/turtle\", extensions = [\"ttl\"]),\n (name = \"text/uri-list\", extensions = [\"uri\",\"uris\",\"urls\"]),\n (name = \"text/vcard\", extensions = [\"vcard\"]),\n (name = \"text/vtt\", extensions = [\"vtt\"]),\n (name = \"text/xml\", extensions = [\"*xml\"]),\n (name = \"text/yaml\", extensions = [\"yaml\",\"yml\"]),\n (name = \"video/3gpp\", extensions = [\"3gp\",\"3gpp\"]),\n (name = \"video/3gpp2\", extensions = [\"3g2\"]),\n (name = \"video/h261\", extensions = [\"h261\"]),\n (name = \"video/h263\", extensions = [\"h263\"]),\n (name = \"video/h264\", extensions = [\"h264\"]),\n (name = \"video/jpeg\", extensions = [\"jpgv\"]),\n (name = \"video/jpm\", extensions = [\"*jpm\",\"jpgm\"]),\n (name = \"video/mj2\", extensions = [\"mj2\",\"mjp2\"]),\n (name = \"video/mp2t\", extensions = [\"ts\"]),\n (name = \"video/mp4\", extensions = [\"mp4\",\"mp4v\",\"mpg4\"]),\n (name = \"video/mpeg\", extensions = [\"mpeg\",\"mpg\",\"mpe\",\"m1v\",\"m2v\"]),\n (name = \"video/ogg\", extensions = [\"ogv\"]),\n (name = \"video/quicktime\", extensions = [\"qt\",\"mov\"]),\n (name = \"video/webm\", extensions = [\"webm\"]),\n (name = \"application/prs.cww\", extensions = [\"cww\"]),\n (name = \"application/vnd.3gpp.pic-bw-large\", extensions = [\"plb\"]),\n (name = \"application/vnd.3gpp.pic-bw-small\", extensions = [\"psb\"]),\n (name = \"application/vnd.3gpp.pic-bw-var\", extensions = [\"pvb\"]),\n (name = \"application/vnd.3gpp2.tcap\", extensions = [\"tcap\"]),\n (name = \"application/vnd.3m.post-it-notes\", extensions = [\"pwn\"]),\n (name = \"application/vnd.accpac.simply.aso\", extensions = [\"aso\"]),\n (name = \"application/vnd.accpac.simply.imp\", extensions = [\"imp\"]),\n (name = \"application/vnd.acucobol\", extensions = [\"acu\"]),\n (name = \"application/vnd.acucorp\", extensions = [\"atc\",\"acutc\"]),\n (name = \"application/vnd.adobe.air-application-installer-package+zip\", extensions = [\"air\"]),\n (name = \"application/vnd.adobe.formscentral.fcdt\", extensions = [\"fcdt\"]),\n (name = \"application/vnd.adobe.fxp\", extensions = [\"fxp\",\"fxpl\"]),\n (name = \"application/vnd.adobe.xdp+xml\", extensions = [\"xdp\"]),\n (name = \"application/vnd.adobe.xfdf\", extensions = [\"xfdf\"]),\n (name = \"application/vnd.ahead.space\", extensions = [\"ahead\"]),\n (name = \"application/vnd.airzip.filesecure.azf\", extensions = [\"azf\"]),\n (name = \"application/vnd.airzip.filesecure.azs\", extensions = [\"azs\"]),\n (name = \"application/vnd.amazon.ebook\", extensions = [\"azw\"]),\n (name = \"application/vnd.americandynamics.acc\", extensions = [\"acc\"]),\n (name = \"application/vnd.amiga.ami\", extensions = [\"ami\"]),\n (name = \"application/vnd.android.package-archive\", extensions = [\"apk\"]),\n (name = \"application/vnd.anser-web-certificate-issue-initiation\", extensions = [\"cii\"]),\n (name = \"application/vnd.anser-web-funds-transfer-initiation\", extensions = [\"fti\"]),\n (name = \"application/vnd.antix.game-component\", extensions = [\"atx\"]),\n (name = \"application/vnd.apple.installer+xml\", extensions = [\"mpkg\"]),\n (name = \"application/vnd.apple.mpegurl\", extensions = [\"m3u8\"]),\n (name = \"application/vnd.apple.pkpass\", extensions = [\"pkpass\"]),\n (name = \"application/vnd.aristanetworks.swi\", extensions = [\"swi\"]),\n (name = \"application/vnd.astraea-software.iota\", extensions = [\"iota\"]),\n (name = \"application/vnd.audiograph\", extensions = [\"aep\"]),\n (name = \"application/vnd.blueice.multipass\", extensions = [\"mpm\"]),\n (name = \"application/vnd.bmi\", extensions = [\"bmi\"]),\n (name = \"application/vnd.businessobjects\", extensions = [\"rep\"]),\n (name = \"application/vnd.chemdraw+xml\", extensions = [\"cdxml\"]),\n (name = \"application/vnd.chipnuts.karaoke-mmd\", extensions = [\"mmd\"]),\n (name = \"application/vnd.cinderella\", extensions = [\"cdy\"]),\n (name = \"application/vnd.claymore\", extensions = [\"cla\"]),\n (name = \"application/vnd.cloanto.rp9\", extensions = [\"rp9\"]),\n (name = \"application/vnd.clonk.c4group\", extensions = [\"c4g\",\"c4d\",\"c4f\",\"c4p\",\"c4u\"]),\n (name = \"application/vnd.cluetrust.cartomobile-config\", extensions = [\"c11amc\"]),\n (name = \"application/vnd.cluetrust.cartomobile-config-pkg\", extensions = [\"c11amz\"]),\n (name = \"application/vnd.commonspace\", extensions = [\"csp\"]),\n (name = \"application/vnd.contact.cmsg\", extensions = [\"cdbcmsg\"]),\n (name = \"application/vnd.cosmocaller\", extensions = [\"cmc\"]),\n (name = \"application/vnd.crick.clicker\", extensions = [\"clkx\"]),\n (name = \"application/vnd.crick.clicker.keyboard\", extensions = [\"clkk\"]),\n (name = \"application/vnd.crick.clicker.palette\", extensions = [\"clkp\"]),\n (name = \"application/vnd.crick.clicker.template\", extensions = [\"clkt\"]),\n (name = \"application/vnd.crick.clicker.wordbank\", extensions = [\"clkw\"]),\n (name = \"application/vnd.criticaltools.wbs+xml\", extensions = [\"wbs\"]),\n (name = \"application/vnd.ctc-posml\", extensions = [\"pml\"]),\n (name = \"application/vnd.cups-ppd\", extensions = [\"ppd\"]),\n (name = \"application/vnd.curl.car\", extensions = [\"car\"]),\n (name = \"application/vnd.curl.pcurl\", extensions = [\"pcurl\"]),\n (name = \"application/vnd.dart\", extensions = [\"dart\"]),\n (name = \"application/vnd.data-vision.rdz\", extensions = [\"rdz\"]),\n (name = \"application/vnd.dece.data\", extensions = [\"uvf\",\"uvvf\",\"uvd\",\"uvvd\"]),\n (name = \"application/vnd.dece.ttml+xml\", extensions = [\"uvt\",\"uvvt\"]),\n (name = \"application/vnd.dece.unspecified\", extensions = [\"uvx\",\"uvvx\"]),\n (name = \"application/vnd.dece.zip\", extensions = [\"uvz\",\"uvvz\"]),\n (name = \"application/vnd.denovo.fcselayout-link\", extensions = [\"fe_launch\"]),\n (name = \"application/vnd.dna\", extensions = [\"dna\"]),\n (name = \"application/vnd.dolby.mlp\", extensions = [\"mlp\"]),\n (name = \"application/vnd.dpgraph\", extensions = [\"dpg\"]),\n (name = \"application/vnd.dreamfactory\", extensions = [\"dfac\"]),\n (name = \"application/vnd.ds-keypoint\", extensions = [\"kpxx\"]),\n (name = \"application/vnd.dvb.ait\", extensions = [\"ait\"]),\n (name = \"application/vnd.dvb.service\", extensions = [\"svc\"]),\n (name = \"application/vnd.dynageo\", extensions = [\"geo\"]),\n (name = \"application/vnd.ecowin.chart\", extensions = [\"mag\"]),\n (name = \"application/vnd.enliven\", extensions = [\"nml\"]),\n (name = \"application/vnd.epson.esf\", extensions = [\"esf\"]),\n (name = \"application/vnd.epson.msf\", extensions = [\"msf\"]),\n (name = \"application/vnd.epson.quickanime\", extensions = [\"qam\"]),\n (name = \"application/vnd.epson.salt\", extensions = [\"slt\"]),\n (name = \"application/vnd.epson.ssf\", extensions = [\"ssf\"]),\n (name = \"application/vnd.eszigno3+xml\", extensions = [\"es3\",\"et3\"]),\n (name = \"application/vnd.ezpix-album\", extensions = [\"ez2\"]),\n (name = \"application/vnd.ezpix-package\", extensions = [\"ez3\"]),\n (name = \"application/vnd.fdf\", extensions = [\"fdf\"]),\n (name = \"application/vnd.fdsn.mseed\", extensions = [\"mseed\"]),\n (name = \"application/vnd.fdsn.seed\", extensions = [\"seed\",\"dataless\"]),\n (name = \"application/vnd.flographit\", extensions = [\"gph\"]),\n (name = \"application/vnd.fluxtime.clip\", extensions = [\"ftc\"]),\n (name = \"application/vnd.framemaker\", extensions = [\"fm\",\"frame\",\"maker\",\"book\"]),\n (name = \"application/vnd.frogans.fnc\", extensions = [\"fnc\"]),\n (name = \"application/vnd.frogans.ltf\", extensions = [\"ltf\"]),\n (name = \"application/vnd.fsc.weblaunch\", extensions = [\"fsc\"]),\n (name = \"application/vnd.fujitsu.oasys\", extensions = [\"oas\"]),\n (name = \"application/vnd.fujitsu.oasys2\", extensions = [\"oa2\"]),\n (name = \"application/vnd.fujitsu.oasys3\", extensions = [\"oa3\"]),\n (name = \"application/vnd.fujitsu.oasysgp\", extensions = [\"fg5\"]),\n (name = \"application/vnd.fujitsu.oasysprs\", extensions = [\"bh2\"]),\n (name = \"application/vnd.fujixerox.ddd\", extensions = [\"ddd\"]),\n (name = \"application/vnd.fujixerox.docuworks\", extensions = [\"xdw\"]),\n (name = \"application/vnd.fujixerox.docuworks.binder\", extensions = [\"xbd\"]),\n (name = \"application/vnd.fuzzysheet\", extensions = [\"fzs\"]),\n (name = \"application/vnd.genomatix.tuxedo\", extensions = [\"txd\"]),\n (name = \"application/vnd.geogebra.file\", extensions = [\"ggb\"]),\n (name = \"application/vnd.geogebra.tool\", extensions = [\"ggt\"]),\n (name = \"application/vnd.geometry-explorer\", extensions = [\"gex\",\"gre\"]),\n (name = \"application/vnd.geonext\", extensions = [\"gxt\"]),\n (name = \"application/vnd.geoplan\", extensions = [\"g2w\"]),\n (name = \"application/vnd.geospace\", extensions = [\"g3w\"]),\n (name = \"application/vnd.gmx\", extensions = [\"gmx\"]),\n (name = \"application/vnd.google-apps.document\", extensions = [\"gdoc\"]),\n (name = \"application/vnd.google-apps.presentation\", extensions = [\"gslides\"]),\n (name = \"application/vnd.google-apps.spreadsheet\", extensions = [\"gsheet\"]),\n (name = \"application/vnd.google-earth.kml+xml\", extensions = [\"kml\"]),\n (name = \"application/vnd.google-earth.kmz\", extensions = [\"kmz\"]),\n (name = \"application/vnd.grafeq\", extensions = [\"gqf\",\"gqs\"]),\n (name = \"application/vnd.groove-account\", extensions = [\"gac\"]),\n (name = \"application/vnd.groove-help\", extensions = [\"ghf\"]),\n (name = \"application/vnd.groove-identity-message\", extensions = [\"gim\"]),\n (name = \"application/vnd.groove-injector\", extensions = [\"grv\"]),\n (name = \"application/vnd.groove-tool-message\", extensions = [\"gtm\"]),\n (name = \"application/vnd.groove-tool-template\", extensions = [\"tpl\"]),\n (name = \"application/vnd.groove-vcard\", extensions = [\"vcg\"]),\n (name = \"application/vnd.hal+xml\", extensions = [\"hal\"]),\n (name = \"application/vnd.handheld-entertainment+xml\", extensions = [\"zmm\"]),\n (name = \"application/vnd.hbci\", extensions = [\"hbci\"]),\n (name = \"application/vnd.hhe.lesson-player\", extensions = [\"les\"]),\n (name = \"application/vnd.hp-hpgl\", extensions = [\"hpgl\"]),\n (name = \"application/vnd.hp-hpid\", extensions = [\"hpid\"]),\n (name = \"application/vnd.hp-hps\", extensions = [\"hps\"]),\n (name = \"application/vnd.hp-jlyt\", extensions = [\"jlt\"]),\n (name = \"application/vnd.hp-pcl\", extensions = [\"pcl\"]),\n (name = \"application/vnd.hp-pclxl\", extensions = [\"pclxl\"]),\n (name = \"application/vnd.hydrostatix.sof-data\", extensions = [\"sfd-hdstx\"]),\n (name = \"application/vnd.ibm.minipay\", extensions = [\"mpy\"]),\n (name = \"application/vnd.ibm.modcap\", extensions = [\"afp\",\"listafp\",\"list3820\"]),\n (name = \"application/vnd.ibm.rights-management\", extensions = [\"irm\"]),\n (name = \"application/vnd.ibm.secure-container\", extensions = [\"sc\"]),\n (name = \"application/vnd.iccprofile\", extensions = [\"icc\",\"icm\"]),\n (name = \"application/vnd.igloader\", extensions = [\"igl\"]),\n (name = \"application/vnd.immervision-ivp\", extensions = [\"ivp\"]),\n (name = \"application/vnd.immervision-ivu\", extensions = [\"ivu\"]),\n (name = \"application/vnd.insors.igm\", extensions = [\"igm\"]),\n (name = \"application/vnd.intercon.formnet\", extensions = [\"xpw\",\"xpx\"]),\n (name = \"application/vnd.intergeo\", extensions = [\"i2g\"]),\n (name = \"application/vnd.intu.qbo\", extensions = [\"qbo\"]),\n (name = \"application/vnd.intu.qfx\", extensions = [\"qfx\"]),\n (name = \"application/vnd.ipunplugged.rcprofile\", extensions = [\"rcprofile\"]),\n (name = \"application/vnd.irepository.package+xml\", extensions = [\"irp\"]),\n (name = \"application/vnd.is-xpr\", extensions = [\"xpr\"]),\n (name = \"application/vnd.isac.fcs\", extensions = [\"fcs\"]),\n (name = \"application/vnd.jam\", extensions = [\"jam\"]),\n (name = \"application/vnd.jcp.javame.midlet-rms\", extensions = [\"rms\"]),\n (name = \"application/vnd.jisp\", extensions = [\"jisp\"]),\n (name = \"application/vnd.joost.joda-archive\", extensions = [\"joda\"]),\n (name = \"application/vnd.kahootz\", extensions = [\"ktz\",\"ktr\"]),\n (name = \"application/vnd.kde.karbon\", extensions = [\"karbon\"]),\n (name = \"application/vnd.kde.kchart\", extensions = [\"chrt\"]),\n (name = \"application/vnd.kde.kformula\", extensions = [\"kfo\"]),\n (name = \"application/vnd.kde.kivio\", extensions = [\"flw\"]),\n (name = \"application/vnd.kde.kontour\", extensions = [\"kon\"]),\n (name = \"application/vnd.kde.kpresenter\", extensions = [\"kpr\",\"kpt\"]),\n (name = \"application/vnd.kde.kspread\", extensions = [\"ksp\"]),\n (name = \"application/vnd.kde.kword\", extensions = [\"kwd\",\"kwt\"]),\n (name = \"application/vnd.kenameaapp\", extensions = [\"htke\"]),\n (name = \"application/vnd.kidspiration\", extensions = [\"kia\"]),\n (name = \"application/vnd.kinar\", extensions = [\"kne\",\"knp\"]),\n (name = \"application/vnd.koan\", extensions = [\"skp\",\"skd\",\"skt\",\"skm\"]),\n (name = \"application/vnd.kodak-descriptor\", extensions = [\"sse\"]),\n (name = \"application/vnd.las.las+xml\", extensions = [\"lasxml\"]),\n (name = \"application/vnd.llamagraphics.life-balance.desktop\", extensions = [\"lbd\"]),\n (name = \"application/vnd.llamagraphics.life-balance.exchange+xml\", extensions = [\"lbe\"]),\n (name = \"application/vnd.lotus-1-2-3\", extensions = [\"123\"]),\n (name = \"application/vnd.lotus-approach\", extensions = [\"apr\"]),\n (name = \"application/vnd.lotus-freelance\", extensions = [\"pre\"]),\n (name = \"application/vnd.lotus-notes\", extensions = [\"nsf\"]),\n (name = \"application/vnd.lotus-organizer\", extensions = [\"org\"]),\n (name = \"application/vnd.lotus-screencam\", extensions = [\"scm\"]),\n (name = \"application/vnd.lotus-wordpro\", extensions = [\"lwp\"]),\n (name = \"application/vnd.macports.portpkg\", extensions = [\"portpkg\"]),\n (name = \"application/vnd.mcd\", extensions = [\"mcd\"]),\n (name = \"application/vnd.medcalcdata\", extensions = [\"mc1\"]),\n (name = \"application/vnd.mediastation.cdkey\", extensions = [\"cdkey\"]),\n (name = \"application/vnd.mfer\", extensions = [\"mwf\"]),\n (name = \"application/vnd.mfmp\", extensions = [\"mfm\"]),\n (name = \"application/vnd.micrografx.flo\", extensions = [\"flo\"]),\n (name = \"application/vnd.micrografx.igx\", extensions = [\"igx\"]),\n (name = \"application/vnd.mif\", extensions = [\"mif\"]),\n (name = \"application/vnd.mobius.daf\", extensions = [\"daf\"]),\n (name = \"application/vnd.mobius.dis\", extensions = [\"dis\"]),\n (name = \"application/vnd.mobius.mbk\", extensions = [\"mbk\"]),\n (name = \"application/vnd.mobius.mqy\", extensions = [\"mqy\"]),\n (name = \"application/vnd.mobius.msl\", extensions = [\"msl\"]),\n (name = \"application/vnd.mobius.plc\", extensions = [\"plc\"]),\n (name = \"application/vnd.mobius.txf\", extensions = [\"txf\"]),\n (name = \"application/vnd.mophun.application\", extensions = [\"mpn\"]),\n (name = \"application/vnd.mophun.certificate\", extensions = [\"mpc\"]),\n (name = \"application/vnd.mozilla.xul+xml\", extensions = [\"xul\"]),\n (name = \"application/vnd.ms-artgalry\", extensions = [\"cil\"]),\n (name = \"application/vnd.ms-cab-compressed\", extensions = [\"cab\"]),\n (name = \"application/vnd.ms-excel\", extensions = [\"xls\",\"xlm\",\"xla\",\"xlc\",\"xlt\",\"xlw\"]),\n (name = \"application/vnd.ms-excel.addin.macroenabled.12\", extensions = [\"xlam\"]),\n (name = \"application/vnd.ms-excel.sheet.binary.macroenabled.12\", extensions = [\"xlsb\"]),\n (name = \"application/vnd.ms-excel.sheet.macroenabled.12\", extensions = [\"xlsm\"]),\n (name = \"application/vnd.ms-excel.template.macroenabled.12\", extensions = [\"xltm\"]),\n (name = \"application/vnd.ms-fontobject\", extensions = [\"eot\"]),\n (name = \"application/vnd.ms-htmlhelp\", extensions = [\"chm\"]),\n (name = \"application/vnd.ms-ims\", extensions = [\"ims\"]),\n (name = \"application/vnd.ms-lrm\", extensions = [\"lrm\"]),\n (name = \"application/vnd.ms-officetheme\", extensions = [\"thmx\"]),\n (name = \"application/vnd.ms-outlook\", extensions = [\"msg\"]),\n (name = \"application/vnd.ms-pki.seccat\", extensions = [\"cat\"]),\n (name = \"application/vnd.ms-pki.stl\", extensions = [\"stl\"]),\n (name = \"application/vnd.ms-powerpoint\", extensions = [\"ppt\",\"pps\",\"pot\"]),\n (name = \"application/vnd.ms-powerpoint.addin.macroenabled.12\", extensions = [\"ppam\"]),\n (name = \"application/vnd.ms-powerpoint.presentation.macroenabled.12\", extensions = [\"pptm\"]),\n (name = \"application/vnd.ms-powerpoint.slide.macroenabled.12\", extensions = [\"sldm\"]),\n (name = \"application/vnd.ms-powerpoint.slideshow.macroenabled.12\", extensions = [\"ppsm\"]),\n (name = \"application/vnd.ms-powerpoint.template.macroenabled.12\", extensions = [\"potm\"]),\n (name = \"application/vnd.ms-project\", extensions = [\"mpp\",\"mpt\"]),\n (name = \"application/vnd.ms-word.document.macroenabled.12\", extensions = [\"docm\"]),\n (name = \"application/vnd.ms-word.template.macroenabled.12\", extensions = [\"dotm\"]),\n (name = \"application/vnd.ms-works\", extensions = [\"wps\",\"wks\",\"wcm\",\"wdb\"]),\n (name = \"application/vnd.ms-wpl\", extensions = [\"wpl\"]),\n (name = \"application/vnd.ms-xpsdocument\", extensions = [\"xps\"]),\n (name = \"application/vnd.mseq\", extensions = [\"mseq\"]),\n (name = \"application/vnd.musician\", extensions = [\"mus\"]),\n (name = \"application/vnd.muvee.style\", extensions = [\"msty\"]),\n (name = \"application/vnd.mynfc\", extensions = [\"taglet\"]),\n (name = \"application/vnd.neurolanguage.nlu\", extensions = [\"nlu\"]),\n (name = \"application/vnd.nitf\", extensions = [\"ntf\",\"nitf\"]),\n (name = \"application/vnd.noblenet-directory\", extensions = [\"nnd\"]),\n (name = \"application/vnd.noblenet-sealer\", extensions = [\"nns\"]),\n (name = \"application/vnd.noblenet-web\", extensions = [\"nnw\"]),\n (name = \"application/vnd.nokia.n-gage.data\", extensions = [\"ngdat\"]),\n (name = \"application/vnd.nokia.n-gage.symbian.install\", extensions = [\"n-gage\"]),\n (name = \"application/vnd.nokia.radio-preset\", extensions = [\"rpst\"]),\n (name = \"application/vnd.nokia.radio-presets\", extensions = [\"rpss\"]),\n (name = \"application/vnd.novadigm.edm\", extensions = [\"edm\"]),\n (name = \"application/vnd.novadigm.edx\", extensions = [\"edx\"]),\n (name = \"application/vnd.novadigm.ext\", extensions = [\"ext\"]),\n (name = \"application/vnd.oasis.opendocument.chart\", extensions = [\"odc\"]),\n (name = \"application/vnd.oasis.opendocument.chart-template\", extensions = [\"otc\"]),\n (name = \"application/vnd.oasis.opendocument.database\", extensions = [\"odb\"]),\n (name = \"application/vnd.oasis.opendocument.formula\", extensions = [\"odf\"]),\n (name = \"application/vnd.oasis.opendocument.formula-template\", extensions = [\"odft\"]),\n (name = \"application/vnd.oasis.opendocument.graphics\", extensions = [\"odg\"]),\n (name = \"application/vnd.oasis.opendocument.graphics-template\", extensions = [\"otg\"]),\n (name = \"application/vnd.oasis.opendocument.image\", extensions = [\"odi\"]),\n (name = \"application/vnd.oasis.opendocument.image-template\", extensions = [\"oti\"]),\n (name = \"application/vnd.oasis.opendocument.presentation\", extensions = [\"odp\"]),\n (name = \"application/vnd.oasis.opendocument.presentation-template\", extensions = [\"otp\"]),\n (name = \"application/vnd.oasis.opendocument.spreadsheet\", extensions = [\"ods\"]),\n (name = \"application/vnd.oasis.opendocument.spreadsheet-template\", extensions = [\"ots\"]),\n (name = \"application/vnd.oasis.opendocument.text\", extensions = [\"odt\"]),\n (name = \"application/vnd.oasis.opendocument.text-master\", extensions = [\"odm\"]),\n (name = \"application/vnd.oasis.opendocument.text-template\", extensions = [\"ott\"]),\n (name = \"application/vnd.oasis.opendocument.text-web\", extensions = [\"oth\"]),\n (name = \"application/vnd.olpc-sugar\", extensions = [\"xo\"]),\n (name = \"application/vnd.oma.dd2+xml\", extensions = [\"dd2\"]),\n (name = \"application/vnd.openofficeorg.extension\", extensions = [\"oxt\"]),\n (name = \"application/vnd.openxmlformats-officedocument.presentationml.presentation\", extensions = [\"pptx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.presentationml.slide\", extensions = [\"sldx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.presentationml.slideshow\", extensions = [\"ppsx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.presentationml.template\", extensions = [\"potx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\", extensions = [\"xlsx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.spreadsheetml.template\", extensions = [\"xltx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", extensions = [\"docx\"]),\n (name = \"application/vnd.openxmlformats-officedocument.wordprocessingml.template\", extensions = [\"dotx\"]),\n (name = \"application/vnd.osgeo.mapguide.package\", extensions = [\"mgp\"]),\n (name = \"application/vnd.osgi.dp\", extensions = [\"dp\"]),\n (name = \"application/vnd.osgi.subsystem\", extensions = [\"esa\"]),\n (name = \"application/vnd.palm\", extensions = [\"pdb\",\"pqa\",\"oprc\"]),\n (name = \"application/vnd.pawaafile\", extensions = [\"paw\"]),\n (name = \"application/vnd.pg.format\", extensions = [\"str\"]),\n (name = \"application/vnd.pg.osasli\", extensions = [\"ei6\"]),\n (name = \"application/vnd.picsel\", extensions = [\"efif\"]),\n (name = \"application/vnd.pmi.widget\", extensions = [\"wg\"]),\n (name = \"application/vnd.pocketlearn\", extensions = [\"plf\"]),\n (name = \"application/vnd.powerbuilder6\", extensions = [\"pbd\"]),\n (name = \"application/vnd.previewsystems.box\", extensions = [\"box\"]),\n (name = \"application/vnd.proteus.magazine\", extensions = [\"mgz\"]),\n (name = \"application/vnd.publishare-delta-tree\", extensions = [\"qps\"]),\n (name = \"application/vnd.pvi.ptid1\", extensions = [\"ptid\"]),\n (name = \"application/vnd.quark.quarkxpress\", extensions = [\"qxd\",\"qxt\",\"qwd\",\"qwt\",\"qxl\",\"qxb\"]),\n (name = \"application/vnd.realvnc.bed\", extensions = [\"bed\"]),\n (name = \"application/vnd.recordare.musicxml\", extensions = [\"mxl\"]),\n (name = \"application/vnd.recordare.musicxml+xml\", extensions = [\"musicxml\"]),\n (name = \"application/vnd.rig.cryptonote\", extensions = [\"cryptonote\"]),\n (name = \"application/vnd.rim.cod\", extensions = [\"cod\"]),\n (name = \"application/vnd.rn-realmedia\", extensions = [\"rm\"]),\n (name = \"application/vnd.rn-realmedia-vbr\", extensions = [\"rmvb\"]),\n (name = \"application/vnd.route66.link66+xml\", extensions = [\"link66\"]),\n (name = \"application/vnd.sailingtracker.track\", extensions = [\"st\"]),\n (name = \"application/vnd.seemail\", extensions = [\"see\"]),\n (name = \"application/vnd.sema\", extensions = [\"sema\"]),\n (name = \"application/vnd.semd\", extensions = [\"semd\"]),\n (name = \"application/vnd.semf\", extensions = [\"semf\"]),\n (name = \"application/vnd.shana.informed.formdata\", extensions = [\"ifm\"]),\n (name = \"application/vnd.shana.informed.formtemplate\", extensions = [\"itp\"]),\n (name = \"application/vnd.shana.informed.interchange\", extensions = [\"iif\"]),\n (name = \"application/vnd.shana.informed.package\", extensions = [\"ipk\"]),\n (name = \"application/vnd.simtech-mindmapper\", extensions = [\"twd\",\"twds\"]),\n (name = \"application/vnd.smaf\", extensions = [\"mmf\"]),\n (name = \"application/vnd.smart.teacher\", extensions = [\"teacher\"]),\n (name = \"application/vnd.solent.sdkm+xml\", extensions = [\"sdkm\",\"sdkd\"]),\n (name = \"application/vnd.spotfire.dxp\", extensions = [\"dxp\"]),\n (name = \"application/vnd.spotfire.sfs\", extensions = [\"sfs\"]),\n (name = \"application/vnd.stardivision.calc\", extensions = [\"sdc\"]),\n (name = \"application/vnd.stardivision.draw\", extensions = [\"sda\"]),\n (name = \"application/vnd.stardivision.impress\", extensions = [\"sdd\"]),\n (name = \"application/vnd.stardivision.math\", extensions = [\"smf\"]),\n (name = \"application/vnd.stardivision.writer\", extensions = [\"sdw\",\"vor\"]),\n (name = \"application/vnd.stardivision.writer-global\", extensions = [\"sgl\"]),\n (name = \"application/vnd.stepmania.package\", extensions = [\"smzip\"]),\n (name = \"application/vnd.stepmania.stepchart\", extensions = [\"sm\"]),\n (name = \"application/vnd.sun.wadl+xml\", extensions = [\"wadl\"]),\n (name = \"application/vnd.sun.xml.calc\", extensions = [\"sxc\"]),\n (name = \"application/vnd.sun.xml.calc.template\", extensions = [\"stc\"]),\n (name = \"application/vnd.sun.xml.draw\", extensions = [\"sxd\"]),\n (name = \"application/vnd.sun.xml.draw.template\", extensions = [\"std\"]),\n (name = \"application/vnd.sun.xml.impress\", extensions = [\"sxi\"]),\n (name = \"application/vnd.sun.xml.impress.template\", extensions = [\"sti\"]),\n (name = \"application/vnd.sun.xml.math\", extensions = [\"sxm\"]),\n (name = \"application/vnd.sun.xml.writer\", extensions = [\"sxw\"]),\n (name = \"application/vnd.sun.xml.writer.global\", extensions = [\"sxg\"]),\n (name = \"application/vnd.sun.xml.writer.template\", extensions = [\"stw\"]),\n (name = \"application/vnd.sus-calendar\", extensions = [\"sus\",\"susp\"]),\n (name = \"application/vnd.svd\", extensions = [\"svd\"]),\n (name = \"application/vnd.symbian.install\", extensions = [\"sis\",\"sisx\"]),\n (name = \"application/vnd.syncml+xml\", extensions = [\"xsm\"]),\n (name = \"application/vnd.syncml.dm+wbxml\", extensions = [\"bdm\"]),\n (name = \"application/vnd.syncml.dm+xml\", extensions = [\"xdm\"]),\n (name = \"application/vnd.tao.intent-module-archive\", extensions = [\"tao\"]),\n (name = \"application/vnd.tcpdump.pcap\", extensions = [\"pcap\",\"cap\",\"dmp\"]),\n (name = \"application/vnd.tmobile-livetv\", extensions = [\"tmo\"]),\n (name = \"application/vnd.trid.tpt\", extensions = [\"tpt\"]),\n (name = \"application/vnd.triscape.mxs\", extensions = [\"mxs\"]),\n (name = \"application/vnd.trueapp\", extensions = [\"tra\"]),\n (name = \"application/vnd.ufdl\", extensions = [\"ufd\",\"ufdl\"]),\n (name = \"application/vnd.uiq.theme\", extensions = [\"utz\"]),\n (name = \"application/vnd.umajin\", extensions = [\"umj\"]),\n (name = \"application/vnd.unity\", extensions = [\"unityweb\"]),\n (name = \"application/vnd.uoml+xml\", extensions = [\"uoml\"]),\n (name = \"application/vnd.vcx\", extensions = [\"vcx\"]),\n (name = \"application/vnd.visio\", extensions = [\"vsd\",\"vst\",\"vss\",\"vsw\"]),\n (name = \"application/vnd.visionary\", extensions = [\"vis\"]),\n (name = \"application/vnd.vsf\", extensions = [\"vsf\"]),\n (name = \"application/vnd.wap.wbxml\", extensions = [\"wbxml\"]),\n (name = \"application/vnd.wap.wmlc\", extensions = [\"wmlc\"]),\n (name = \"application/vnd.wap.wmlscriptc\", extensions = [\"wmlsc\"]),\n (name = \"application/vnd.webturbo\", extensions = [\"wtb\"]),\n (name = \"application/vnd.wolfram.player\", extensions = [\"nbp\"]),\n (name = \"application/vnd.wordperfect\", extensions = [\"wpd\"]),\n (name = \"application/vnd.wqd\", extensions = [\"wqd\"]),\n (name = \"application/vnd.wt.stf\", extensions = [\"stf\"]),\n (name = \"application/vnd.xara\", extensions = [\"xar\"]),\n (name = \"application/vnd.xfdl\", extensions = [\"xfdl\"]),\n (name = \"application/vnd.yamaha.hv-dic\", extensions = [\"hvd\"]),\n (name = \"application/vnd.yamaha.hv-script\", extensions = [\"hvs\"]),\n (name = \"application/vnd.yamaha.hv-voice\", extensions = [\"hvp\"]),\n (name = \"application/vnd.yamaha.openscoreformat\", extensions = [\"osf\"]),\n (name = \"application/vnd.yamaha.openscoreformat.osfpvg+xml\", extensions = [\"osfpvg\"]),\n (name = \"application/vnd.yamaha.smaf-audio\", extensions = [\"saf\"]),\n (name = \"application/vnd.yamaha.smaf-phrase\", extensions = [\"spf\"]),\n (name = \"application/vnd.yellowriver-custom-menu\", extensions = [\"cmp\"]),\n (name = \"application/vnd.zul\", extensions = [\"zir\",\"zirz\"]),\n (name = \"application/vnd.zzazz.deck+xml\", extensions = [\"zaz\"]),\n (name = \"application/x-7z-compressed\", extensions = [\"7z\"]),\n (name = \"application/x-abiword\", extensions = [\"abw\"]),\n (name = \"application/x-ace-compressed\", extensions = [\"ace\"]),\n (name = \"application/x-apple-diskimage\", extensions = [\"*dmg\"]),\n (name = \"application/x-arj\", extensions = [\"arj\"]),\n (name = \"application/x-authorware-bin\", extensions = [\"aab\",\"x32\",\"u32\",\"vox\"]),\n (name = \"application/x-authorware-map\", extensions = [\"aam\"]),\n (name = \"application/x-authorware-seg\", extensions = [\"aas\"]),\n (name = \"application/x-bcpio\", extensions = [\"bcpio\"]),\n (name = \"application/x-bdoc\", extensions = [\"*bdoc\"]),\n (name = \"application/x-bittorrent\", extensions = [\"torrent\"]),\n (name = \"application/x-blorb\", extensions = [\"blb\",\"blorb\"]),\n (name = \"application/x-bzip\", extensions = [\"bz\"]),\n (name = \"application/x-bzip2\", extensions = [\"bz2\",\"boz\"]),\n (name = \"application/x-cbr\", extensions = [\"cbr\",\"cba\",\"cbt\",\"cbz\",\"cb7\"]),\n (name = \"application/x-cdlink\", extensions = [\"vcd\"]),\n (name = \"application/x-cfs-compressed\", extensions = [\"cfs\"]),\n (name = \"application/x-chat\", extensions = [\"chat\"]),\n (name = \"application/x-chess-pgn\", extensions = [\"pgn\"]),\n (name = \"application/x-chrome-extension\", extensions = [\"crx\"]),\n (name = \"application/x-cocoa\", extensions = [\"cco\"]),\n (name = \"application/x-conference\", extensions = [\"nsc\"]),\n (name = \"application/x-cpio\", extensions = [\"cpio\"]),\n (name = \"application/x-csh\", extensions = [\"csh\"]),\n (name = \"application/x-debian-package\", extensions = [\"*deb\",\"udeb\"]),\n (name = \"application/x-dgc-compressed\", extensions = [\"dgc\"]),\n (name = \"application/x-director\", extensions = [\"dir\",\"dcr\",\"dxr\",\"cst\",\"cct\",\"cxt\",\"w3d\",\"fgd\",\"swa\"]),\n (name = \"application/x-doom\", extensions = [\"wad\"]),\n (name = \"application/x-dtbncx+xml\", extensions = [\"ncx\"]),\n (name = \"application/x-dtbook+xml\", extensions = [\"dtb\"]),\n (name = \"application/x-dtbresource+xml\", extensions = [\"res\"]),\n (name = \"application/x-dvi\", extensions = [\"dvi\"]),\n (name = \"application/x-envoy\", extensions = [\"evy\"]),\n (name = \"application/x-eva\", extensions = [\"eva\"]),\n (name = \"application/x-font-bdf\", extensions = [\"bdf\"]),\n (name = \"application/x-font-ghostscript\", extensions = [\"gsf\"]),\n (name = \"application/x-font-linux-psf\", extensions = [\"psf\"]),\n (name = \"application/x-font-pcf\", extensions = [\"pcf\"]),\n (name = \"application/x-font-snf\", extensions = [\"snf\"]),\n (name = \"application/x-font-type1\", extensions = [\"pfa\",\"pfb\",\"pfm\",\"afm\"]),\n (name = \"application/x-freearc\", extensions = [\"arc\"]),\n (name = \"application/x-futuresplash\", extensions = [\"spl\"]),\n (name = \"application/x-gca-compressed\", extensions = [\"gca\"]),\n (name = \"application/x-glulx\", extensions = [\"ulx\"]),\n (name = \"application/x-gnumeric\", extensions = [\"gnumeric\"]),\n (name = \"application/x-gramps-xml\", extensions = [\"gramps\"]),\n (name = \"application/x-gtar\", extensions = [\"gtar\"]),\n (name = \"application/x-hdf\", extensions = [\"hdf\"]),\n (name = \"application/x-httpd-php\", extensions = [\"php\"]),\n (name = \"application/x-install-instructions\", extensions = [\"install\"]),\n (name = \"application/x-iso9660-image\", extensions = [\"*iso\"]),\n (name = \"application/x-java-archive-diff\", extensions = [\"jardiff\"]),\n (name = \"application/x-java-jnlp-file\", extensions = [\"jnlp\"]),\n (name = \"application/x-latex\", extensions = [\"latex\"]),\n (name = \"application/x-lua-bytecode\", extensions = [\"luac\"]),\n (name = \"application/x-lzh-compressed\", extensions = [\"lzh\",\"lha\"]),\n (name = \"application/x-makeself\", extensions = [\"run\"]),\n (name = \"application/x-mie\", extensions = [\"mie\"]),\n (name = \"application/x-mobipocket-ebook\", extensions = [\"prc\",\"mobi\"]),\n (name = \"application/x-ms-application\", extensions = [\"application\"]),\n (name = \"application/x-ms-shortcut\", extensions = [\"lnk\"]),\n (name = \"application/x-ms-wmd\", extensions = [\"wmd\"]),\n (name = \"application/x-ms-wmz\", extensions = [\"wmz\"]),\n (name = \"application/x-ms-xbap\", extensions = [\"xbap\"]),\n (name = \"application/x-msaccess\", extensions = [\"mdb\"]),\n (name = \"application/x-msbinder\", extensions = [\"obd\"]),\n (name = \"application/x-mscardfile\", extensions = [\"crd\"]),\n (name = \"application/x-msclip\", extensions = [\"clp\"]),\n (name = \"application/x-msdos-program\", extensions = [\"*exe\"]),\n (name = \"application/x-msdownload\", extensions = [\"*exe\",\"*dll\",\"com\",\"bat\",\"*msi\"]),\n (name = \"application/x-msmediaview\", extensions = [\"mvb\",\"m13\",\"m14\"]),\n (name = \"application/x-msmetafile\", extensions = [\"wmf\",\"*wmz\",\"emf\",\"emz\"]),\n (name = \"application/x-msmoney\", extensions = [\"mny\"]),\n (name = \"application/x-mspublisher\", extensions = [\"pub\"]),\n (name = \"application/x-msschedule\", extensions = [\"scd\"]),\n (name = \"application/x-msterminal\", extensions = [\"trm\"]),\n (name = \"application/x-mswrite\", extensions = [\"wri\"]),\n (name = \"application/x-netcdf\", extensions = [\"nc\",\"cdf\"]),\n (name = \"application/x-ns-proxy-autoconfig\", extensions = [\"pac\"]),\n (name = \"application/x-nzb\", extensions = [\"nzb\"]),\n (name = \"application/x-perl\", extensions = [\"pl\",\"pm\"]),\n (name = \"application/x-pilot\", extensions = [\"*prc\",\"*pdb\"]),\n (name = \"application/x-pkcs12\", extensions = [\"p12\",\"pfx\"]),\n (name = \"application/x-pkcs7-certificates\", extensions = [\"p7b\",\"spc\"]),\n (name = \"application/x-pkcs7-certreqresp\", extensions = [\"p7r\"]),\n (name = \"application/x-rar-compressed\", extensions = [\"rar\"]),\n (name = \"application/x-redhat-package-manager\", extensions = [\"rpm\"]),\n (name = \"application/x-research-info-systems\", extensions = [\"ris\"]),\n (name = \"application/x-sea\", extensions = [\"sea\"]),\n (name = \"application/x-sh\", extensions = [\"sh\"]),\n (name = \"application/x-shar\", extensions = [\"shar\"]),\n (name = \"application/x-shockwave-flash\", extensions = [\"swf\"]),\n (name = \"application/x-silverlight-app\", extensions = [\"xap\"]),\n (name = \"application/x-sql\", extensions = [\"sql\"]),\n (name = \"application/x-stuffit\", extensions = [\"sit\"]),\n (name = \"application/x-stuffitx\", extensions = [\"sitx\"]),\n (name = \"application/x-subrip\", extensions = [\"srt\"]),\n (name = \"application/x-sv4cpio\", extensions = [\"sv4cpio\"]),\n (name = \"application/x-sv4crc\", extensions = [\"sv4crc\"]),\n (name = \"application/x-t3vm-image\", extensions = [\"t3\"]),\n (name = \"application/x-tads\", extensions = [\"gam\"]),\n (name = \"application/x-tar\", extensions = [\"tar\"]),\n (name = \"application/x-tcl\", extensions = [\"tcl\",\"tk\"]),\n (name = \"application/x-tex\", extensions = [\"tex\"]),\n (name = \"application/x-tex-tfm\", extensions = [\"tfm\"]),\n (name = \"application/x-texinfo\", extensions = [\"texinfo\",\"texi\"]),\n (name = \"application/x-tgif\", extensions = [\"obj\"]),\n (name = \"application/x-ustar\", extensions = [\"ustar\"]),\n (name = \"application/x-virtualbox-hdd\", extensions = [\"hdd\"]),\n (name = \"application/x-virtualbox-ova\", extensions = [\"ova\"]),\n (name = \"application/x-virtualbox-ovf\", extensions = [\"ovf\"]),\n (name = \"application/x-virtualbox-vbox\", extensions = [\"vbox\"]),\n (name = \"application/x-virtualbox-vbox-extpack\", extensions = [\"vbox-extpack\"]),\n (name = \"application/x-virtualbox-vdi\", extensions = [\"vdi\"]),\n (name = \"application/x-virtualbox-vhd\", extensions = [\"vhd\"]),\n (name = \"application/x-virtualbox-vmdk\", extensions = [\"vmdk\"]),\n (name = \"application/x-wais-source\", extensions = [\"src\"]),\n (name = \"application/x-web-app-manifest+json\", extensions = [\"webapp\"]),\n (name = \"application/x-x509-ca-cert\", extensions = [\"der\",\"crt\",\"pem\"]),\n (name = \"application/x-xfig\", extensions = [\"fig\"]),\n (name = \"application/x-xliff+xml\", extensions = [\"xlf\"]),\n (name = \"application/x-xpinstall\", extensions = [\"xpi\"]),\n (name = \"application/x-xz\", extensions = [\"xz\"]),\n (name = \"application/x-zmachine\", extensions = [\"z1\",\"z2\",\"z3\",\"z4\",\"z5\",\"z6\",\"z7\",\"z8\"]),\n (name = \"audio/vnd.dece.audio\", extensions = [\"uva\",\"uvva\"]),\n (name = \"audio/vnd.digital-winds\", extensions = [\"eol\"]),\n (name = \"audio/vnd.dra\", extensions = [\"dra\"]),\n (name = \"audio/vnd.dts\", extensions = [\"dts\"]),\n (name = \"audio/vnd.dts.hd\", extensions = [\"dtshd\"]),\n (name = \"audio/vnd.lucent.voice\", extensions = [\"lvp\"]),\n (name = \"audio/vnd.ms-playready.media.pya\", extensions = [\"pya\"]),\n (name = \"audio/vnd.nuera.ecelp4800\", extensions = [\"ecelp4800\"]),\n (name = \"audio/vnd.nuera.ecelp7470\", extensions = [\"ecelp7470\"]),\n (name = \"audio/vnd.nuera.ecelp9600\", extensions = [\"ecelp9600\"]),\n (name = \"audio/vnd.rip\", extensions = [\"rip\"]),\n (name = \"audio/x-aac\", extensions = [\"aac\"]),\n (name = \"audio/x-aiff\", extensions = [\"aif\",\"aiff\",\"aifc\"]),\n (name = \"audio/x-caf\", extensions = [\"caf\"]),\n (name = \"audio/x-flac\", extensions = [\"flac\"]),\n (name = \"audio/x-m4a\", extensions = [\"*m4a\"]),\n (name = \"audio/x-matroska\", extensions = [\"mka\"]),\n (name = \"audio/x-mpegurl\", extensions = [\"m3u\"]),\n (name = \"audio/x-ms-wax\", extensions = [\"wax\"]),\n (name = \"audio/x-ms-wma\", extensions = [\"wma\"]),\n (name = \"audio/x-pn-realaudio\", extensions = [\"ram\",\"ra\"]),\n (name = \"audio/x-pn-realaudio-plugin\", extensions = [\"rmp\"]),\n (name = \"audio/x-realaudio\", extensions = [\"*ra\"]),\n (name = \"audio/x-wav\", extensions = [\"*wav\"]),\n (name = \"chemical/x-cdx\", extensions = [\"cdx\"]),\n (name = \"chemical/x-cif\", extensions = [\"cif\"]),\n (name = \"chemical/x-cmdf\", extensions = [\"cmdf\"]),\n (name = \"chemical/x-cml\", extensions = [\"cml\"]),\n (name = \"chemical/x-csml\", extensions = [\"csml\"]),\n (name = \"chemical/x-xyz\", extensions = [\"xyz\"]),\n (name = \"image/prs.btif\", extensions = [\"btif\"]),\n (name = \"image/vnd.adobe.photoshop\", extensions = [\"psd\"]),\n (name = \"image/vnd.dece.graphic\", extensions = [\"uvi\",\"uvvi\",\"uvg\",\"uvvg\"]),\n (name = \"image/vnd.djvu\", extensions = [\"djvu\",\"djv\"]),\n (name = \"image/vnd.dvb.subtitle\", extensions = [\"*sub\"]),\n (name = \"image/vnd.dwg\", extensions = [\"dwg\"]),\n (name = \"image/vnd.dxf\", extensions = [\"dxf\"]),\n (name = \"image/vnd.fastbidsheet\", extensions = [\"fbs\"]),\n (name = \"image/vnd.fpx\", extensions = [\"fpx\"]),\n (name = \"image/vnd.fst\", extensions = [\"fst\"]),\n (name = \"image/vnd.fujixerox.edmics-mmr\", extensions = [\"mmr\"]),\n (name = \"image/vnd.fujixerox.edmics-rlc\", extensions = [\"rlc\"]),\n (name = \"image/vnd.ms-modi\", extensions = [\"mdi\"]),\n (name = \"image/vnd.ms-photo\", extensions = [\"wdp\"]),\n (name = \"image/vnd.net-fpx\", extensions = [\"npx\"]),\n (name = \"image/vnd.wap.wbmp\", extensions = [\"wbmp\"]),\n (name = \"image/vnd.xiff\", extensions = [\"xif\"]),\n (name = \"image/x-3ds\", extensions = [\"3ds\"]),\n (name = \"image/x-cmu-raster\", extensions = [\"ras\"]),\n (name = \"image/x-cmx\", extensions = [\"cmx\"]),\n (name = \"image/x-freehand\", extensions = [\"fh\",\"fhc\",\"fh4\",\"fh5\",\"fh7\"]),\n (name = \"image/x-icon\", extensions = [\"ico\"]),\n (name = \"image/x-jng\", extensions = [\"jng\"]),\n (name = \"image/x-mrsid-image\", extensions = [\"sid\"]),\n (name = \"image/x-ms-bmp\", extensions = [\"*bmp\"]),\n (name = \"image/x-pcx\", extensions = [\"pcx\"]),\n (name = \"image/x-pict\", extensions = [\"pic\",\"pct\"]),\n (name = \"image/x-portable-anymap\", extensions = [\"pnm\"]),\n (name = \"image/x-portable-bitmap\", extensions = [\"pbm\"]),\n (name = \"image/x-portable-graymap\", extensions = [\"pgm\"]),\n (name = \"image/x-portable-pixmap\", extensions = [\"ppm\"]),\n (name = \"image/x-rgb\", extensions = [\"rgb\"]),\n (name = \"image/x-tga\", extensions = [\"tga\"]),\n (name = \"image/x-xbitmap\", extensions = [\"xbm\"]),\n (name = \"image/x-xpixmap\", extensions = [\"xpm\"]),\n (name = \"image/x-xwindowdump\", extensions = [\"xwd\"]),\n (name = \"model/vnd.collada+xml\", extensions = [\"dae\"]),\n (name = \"model/vnd.dwf\", extensions = [\"dwf\"]),\n (name = \"model/vnd.gdl\", extensions = [\"gdl\"]),\n (name = \"model/vnd.gtw\", extensions = [\"gtw\"]),\n (name = \"model/vnd.mts\", extensions = [\"mts\"]),\n (name = \"model/vnd.vtu\", extensions = [\"vtu\"]),\n (name = \"text/prs.lines.tag\", extensions = [\"dsc\"]),\n (name = \"text/vnd.curl\", extensions = [\"curl\"]),\n (name = \"text/vnd.curl.dcurl\", extensions = [\"dcurl\"]),\n (name = \"text/vnd.curl.mcurl\", extensions = [\"mcurl\"]),\n (name = \"text/vnd.curl.scurl\", extensions = [\"scurl\"]),\n (name = \"text/vnd.dvb.subtitle\", extensions = [\"sub\"]),\n (name = \"text/vnd.fly\", extensions = [\"fly\"]),\n (name = \"text/vnd.fmi.flexstor\", extensions = [\"flx\"]),\n (name = \"text/vnd.graphviz\", extensions = [\"gv\"]),\n (name = \"text/vnd.in3d.3dml\", extensions = [\"3dml\"]),\n (name = \"text/vnd.in3d.spot\", extensions = [\"spot\"]),\n (name = \"text/vnd.sun.j2me.app-descriptor\", extensions = [\"jad\"]),\n (name = \"text/vnd.wap.wml\", extensions = [\"wml\"]),\n (name = \"text/vnd.wap.wmlscript\", extensions = [\"wmls\"]),\n (name = \"text/x-asm\", extensions = [\"s\",\"asm\"]),\n (name = \"text/x-c\", extensions = [\"c\",\"cc\",\"cxx\",\"cpp\",\"h\",\"hh\",\"dic\"]),\n (name = \"text/x-component\", extensions = [\"htc\"]),\n (name = \"text/x-fortran\", extensions = [\"f\",\"for\",\"f77\",\"f90\"]),\n (name = \"text/x-handlebars-template\", extensions = [\"hbs\"]),\n (name = \"text/x-java-source\", extensions = [\"java\"]),\n (name = \"text/x-lua\", extensions = [\"lua\"]),\n (name = \"text/x-markdown\", extensions = [\"mkd\"]),\n (name = \"text/x-nfo\", extensions = [\"nfo\"]),\n (name = \"text/x-opml\", extensions = [\"opml\"]),\n (name = \"text/x-org\", extensions = [\"*org\"]),\n (name = \"text/x-pascal\", extensions = [\"p\",\"pas\"]),\n (name = \"text/x-processing\", extensions = [\"pde\"]),\n (name = \"text/x-sass\", extensions = [\"sass\"]),\n (name = \"text/x-scss\", extensions = [\"scss\"]),\n (name = \"text/x-setext\", extensions = [\"etx\"]),\n (name = \"text/x-sfv\", extensions = [\"sfv\"]),\n (name = \"text/x-suse-ymp\", extensions = [\"ymp\"]),\n (name = \"text/x-uuencode\", extensions = [\"uu\"]),\n (name = \"text/x-vcalendar\", extensions = [\"vcs\"]),\n (name = \"text/x-vcard\", extensions = [\"vcf\"]),\n (name = \"video/vnd.dece.hd\", extensions = [\"uvh\",\"uvvh\"]),\n (name = \"video/vnd.dece.mobile\", extensions = [\"uvm\",\"uvvm\"]),\n (name = \"video/vnd.dece.pd\", extensions = [\"uvp\",\"uvvp\"]),\n (name = \"video/vnd.dece.sd\", extensions = [\"uvs\",\"uvvs\"]),\n (name = \"video/vnd.dece.video\", extensions = [\"uvv\",\"uvvv\"]),\n (name = \"video/vnd.dvb.file\", extensions = [\"dvb\"]),\n (name = \"video/vnd.fvt\", extensions = [\"fvt\"]),\n (name = \"video/vnd.mpegurl\", extensions = [\"mxu\",\"m4u\"]),\n (name = \"video/vnd.ms-playready.media.pyv\", extensions = [\"pyv\"]),\n (name = \"video/vnd.uvvu.mp4\", extensions = [\"uvu\",\"uvvu\"]),\n (name = \"video/vnd.vivo\", extensions = [\"viv\"]),\n (name = \"video/x-f4v\", extensions = [\"f4v\"]),\n (name = \"video/x-fli\", extensions = [\"fli\"]),\n (name = \"video/x-flv\", extensions = [\"flv\"]),\n (name = \"video/x-m4v\", extensions = [\"m4v\"]),\n (name = \"video/x-matroska\", extensions = [\"mkv\",\"mk3d\",\"mks\"]),\n (name = \"video/x-mng\", extensions = [\"mng\"]),\n (name = \"video/x-ms-asf\", extensions = [\"asf\",\"asx\"]),\n (name = \"video/x-ms-vob\", extensions = [\"vob\"]),\n (name = \"video/x-ms-wm\", extensions = [\"wm\"]),\n (name = \"video/x-ms-wmv\", extensions = [\"wmv\"]),\n (name = \"video/x-ms-wmx\", extensions = [\"wmx\"]),\n (name = \"video/x-ms-wvx\", extensions = [\"wvx\"]),\n (name = \"video/x-msvideo\", extensions = [\"avi\"]),\n (name = \"video/x-sgi-movie\", extensions = [\"movie\"]),\n (name = \"video/x-smv\", extensions = [\"smv\"]),\n (name = \"x-conference/x-cooltalk\", extensions = [\"ice\"]),\n];\n",
"powerbox.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014-2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xf6c200ab14cd53e4;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\n\n# ========================================================================================\n# Powerbox\n#\n# The powerbox is part of the Sandstorm UI which allows users to connect applications to each\n# other. There are two main modes in which a powerbox interaction can be driven: \"request\" and\n# \"offer\".\n#\n# In \"request\" mode, an app initiates the powerbox by requesting to receive a capability matching\n# some particular criteria using `SessionContext.request()` (or through the client-side\n# postMessage() API, described in the documentation for `SessionContext.request()`). The user is\n# presented with a list of other grains of theirs which might be able to fulfill this request and\n# asked to choose one. Other grains initially register their ability to answer certain requests\n# by filling in the powerbox fields of `UiView.ViewInfo`. When the user chooses a grain,\n# `UiView.newRequestSession()` is called on the providing grain and the resulting UI session is\n# displayed embedded in the powerbox. The providing grain can render a UI which prompts the user\n# for additional details if needed, or implements some sort of additional picker. Once the grain\n# knows which capability to provide, it calls `SessionContext.provide()` to fulfill the original\n# request.\n#\n# In \"offer\" mode, an app initiates the powerbox by calling `SessionContext.offer()` in a normal,\n# non-powerbox session, to indicate that it wishes to offer some capability to the current user\n# for use in other apps. The user is presented with a list of apps and grains that are able to\n# accept this offer. Grains can register interest in receiving offers by filling in the powerbox\n# metadata in `UiView.ViewInfo`. Apps can also indicate in their manifest that it makes sense for a\n# user to create a whole new grain to accept a powerbox offer. In either case, a session is created\n# using `UiView.newOfferSession()`.\n\nstruct PowerboxDescriptor {\n # Describes properties of capabilities exported by the powerbox, or capabilities requested\n # through the powerbox.\n #\n # A PowerboxDescriptor specified individually describes the properties of a single object or\n # capability. It is a conjunction of \"tags\" describing different aspects of the object, such as\n # which interfaces it implements.\n #\n # Often, descriptors come in a list, i.e. List(PowerboxDescriptor). Such a list is usually a\n # disjunction describing one of two things:\n # - A powerbox \"query\" is a list of descriptors used in a request to indicate what kinds of\n # objects the requesting app is looking for. (In a powerbox \"offer\" interaction, the \"query\"\n # is the list of descriptors that the accepting app indicated it accepts in its `ViewInfo`.)\n # - A powerbox \"provision\" is a list of descriptors used to describe what kinds of objects an\n # app provides, which can be requested by other apps. (In a powerbox \"offer\" interaction, the\n # \"provision\" consists of the single descriptor that the offering app passed to `offer()`.)\n #\n # For a query to match a provision, at least one descriptor in the query must match at least one\n # descriptor in the provision (with an acceptable `matchQuality`; see below).\n #\n # Note that, in some use cases, where the \"object\" being granted is in fact just static data,\n # that data may be entirely encoded in tags, and the object itself may be a null capability.\n # For example, a powerbox request for a \"contact\" may result in a null capability with a tag\n # containing the contact details. Apps are free to define such conventions as they see fit; it\n # makes no difference to the system.\n\n tags @0 :List(Tag);\n # List of tags. For a query descriptor to match a provision descriptor, every tag in the query\n # must be matched by at least one tag in the provision. If the query tags list is empty, then\n # the query is asking for any capability at all; this occasionally makes sense in \"meta\" apps\n # that organize or communicate general capabilities.\n\n struct Tag {\n id @0 :UInt64;\n # A unique ID naming the tag. All such IDs should be created using `capnp id`.\n #\n # It is up to the developer who creates a new ID to decide what type the tag's `value` should\n # have (if any). This should be documented where the ID is defined, e.g.:\n #\n # const preferredFrobberTag :UInt64 = 0xa170f46ec4b17829;\n # # The value should be of type `Text` naming the object's preferred frobber.\n #\n # By convention, however, a tag ID is *usually* a Cap'n Proto type ID, with the following\n # meanings:\n #\n # * If `id` is the Cap'n Proto type ID of an interface, it indicates that the described\n # powerbox capability will implement this interface. The interface's documentation may define\n # what `value` should be in this case; otherwise, it should be null. (For example, a \"file\"\n # interface might define that the `value` should be some sort of type descriptor, such as a\n # MIME type. Most interfaces, however, will not define any `value`; the mere fact that the\n # object implements the interface is the important part.)\n #\n # * If `id` is the type ID of a struct type, then `value` is an instance of that struct type.\n # The struct type's documentation describes how the tag is to be interpreted.\n #\n # Note that these are merely conventions; nothing in the system actually expects tag IDs to\n # match Cap'n Proto type IDs, except possibly debugging tools.\n\n value @1 :AnyPointer;\n # An arbitrary value expressing additional metadata related to the tag.\n #\n # This is optional. \"Boolean\" tags (where all that matters is that they are present or\n # absent) -- including tags that merely indicate that an interface is implemented -- may leave\n # this field null.\n #\n # When \"matching\" two descriptors (one of which is a \"query\", and the other of which describes\n # a \"provision\"), the following algorithm is used to decide if they match:\n #\n # * A null pointer matches any value (essentially, null = wildcard).\n # * Pointers pointing to different object types (e.g. struct vs. list) do not match.\n # * Two struct pointers match if the primitive fields in both structs have identical values\n # (bit for bit) and the corresponding pointer fields match by applying this algorithm\n # recursively.\n # * Two lists of non-struct elements match if their contents match exactly.\n # * Lists of structs are treated as *sets*. They match if every element in the query list\n # matches at least one element in the provider list. Order of elements is irrelevant.\n #\n # The above algorithm may appear quirky, but is designed to cover common use cases while being\n # relatively simple to implement. Consider, for example, a powerbox query seeking to match\n # \"video files\". All \"files\" are just byte blobs; file managers probably don't implement\n # different interfaces for different file types. So, you will want to use tags here. For\n # example, a MIME type tag might be defined as:\n #\n # struct MimeType {\n # category @0 :Text;\n # subtype @1 :Text;\n # tree @2 :Text; // e.g. \"vnd\"\n # suffix @3 :Text; // e.g. \"xml\"\n # params @4 :List(Param);\n # struct Param {\n # name @0 :Text;\n # value @1 :Text;\n # }\n # }\n #\n # You might then express your query with a tag with `id` = MimeType's type ID and value =\n # `(category = \"video\")`, which effectively translates to a query for \"video/*\". (Your query\n # descriptor would have a second tag to indicate what Cap'n Proto interface the resulting\n # capability should implement.)\n }\n\n quality @1 :MatchQuality = acceptable;\n # Use to indicate a preference or anti-preference for this descriptor compared to others in the\n # same list.\n #\n # When a descriptor in the query matches multiple descriptors in the provision, or vice versa,\n # exactly one of the matches is chosen to decide the overall `matchQuality`, as follows:\n # - If one matching descriptor is strictly less-specific than some other in the match set, it is\n # discarded. (A descriptor A is strictly less-specific than a descriptor B if every possible\n # match for B would also match A.)\n # - Once all less-specific descriptors are eliminated, of those that remains, the descriptor with\n # the best `matchQuality` is chosen.\n\n enum MatchQuality {\n # The values below are listed in order from \"best\" to \"worst\". Note that this ordering does NOT\n # correspond to the numeric order. Also note that new values could be introduced in the future.\n\n preferred @1;\n # Indicates that this match should be preferred over other options. The powerbox UI may\n # encourage the user to choose preferred options. For example, a document editor that uses\n # the powerbox to import document files might indicate that it accepts docx format but prefers\n # odf, perhaps because its importer for the latter is higher-quality. Similarly, it might\n # publish powerbox capabilities to export as either format, but again mark odf as preferred.\n #\n # Note `preferred` is only meaningful if the descriptor list contains other descriptors that\n # are marked `acceptable`. An app cannot promote itself over other apps by marking its\n # provisions as `preferred`. (A requesting app could indicate a preference for a particular\n # providing app, though, if the providing app provides a unique tag that the requestor can\n # mark as preferred.)\n\n acceptable @0;\n # Indicates that this is a fine match which should be offered to the user as a regular option.\n # This is the default.\n\n # TODO(someday): mightWork @3;\n # Indicates that the match might have useful results but there is a non-negligible priority\n # that it won't work, and this option should be offered to the user only as an advanced option.\n\n unacceptable @2;\n # \"Unacceptable\" matches are expected *not* to work and therefore will not be offered to the\n # user.\n #\n # Note that `unacceptable` can be used to filter out a subset of matches of a broader\n # descriptor by taking advantage of the fact that the powerbox prefers more-specific matches\n # over less-specific ones. For instance, you could query for \"files except video files\" by\n # specifying a query with two descriptors: a descriptor for \"implements File\" with quality\n # \"acceptable\" and a second descriptor for \"implements File with type = video\" with quality\n # \"unacceptable\".\n }\n}\n\nstruct PowerboxDisplayInfo {\n # Information about a powerbox link (i.e., the result of a powerbox interaction) which could be\n # displayed to the user when auditing powerbox-granted capabilities.\n\n title @0 :Util.LocalizedText;\n # A short, human-readable noun phrase describing the object this capability represents. If null,\n # the grain's title will be used -- this is appropriate if the capability effectively represents\n # the whole grain.\n #\n # The title is used, for example, when the user is selecting multiple capabilities, building a\n # list.\n\n verbPhrase @1 :Util.LocalizedText;\n # Verb phrase describing what the holder of this capability can do to the grain, e.g.\n # \"can edit\". This may be displayed in the sharing UI to describe a connection between two\n # grains.\n\n description @2 :Util.LocalizedText;\n # Long-form description of what the capability represents. Should be roughly a paragraph that\n # could be displayed e.g. in a tooltip.\n}\n",
"api-session-impl.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xa949cfa7be07085b;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing ApiSession = import \"api-session.capnp\".ApiSession;\nusing SystemPersistent = import \"supervisor.capnp\".SystemPersistent;\n\ninterface PersistentApiSession extends (ApiSession, SystemPersistent) {}\n",
"hack-session.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xbf6889795837d1e0;\n# This file defines some hacks added on top of the grain session protocol designed to expose some\n# basic ways to communicate with the outside world (such as e-mail) without requiring persistent\n# capabilities nor the Powerbox (which will take some time to implement). Once the Powerbox is\n# available, these hacks should go away. Consider them pre-deprecated.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Grain = import \"grain.capnp\";\nusing Email = import \"email.capnp\";\nusing Ip = import \"ip.capnp\";\nusing Identity = import \"identity.capnp\";\n\ninterface HackSessionContext @0xe14c1f5321159b8f\n extends(Grain.SessionContext, Email.EmailSendPort) {\n # The SessionContext passed to a grain when newSession() is called is actually of type\n # HackSessionContext. This is the case both when opening HackEmailSessions (below) and regular\n # WebSessions.\n\n getPublicId @0 () -> (publicId :Text, hostname :Text, autoUrl :Text, isDemoUser :Bool);\n # Get the grain's public ID, assigning one if it isn't already assigned. The public ID is used\n # as the e-mail address and for serving static content.\n #\n # If `autoUrl` is non-null, it is an automatically-assigned URL at which the grain's public\n # web content is already visible.\n #\n # If `isDemoUser` is true, the user is a temporary demo account. In this case the app probably\n # should *not* suggest setting up DNS because the grain will disappear soon anyway. (Also our\n # main demo server doesn't support web publishing to arbitrary domains due to sharing an IP\n # address with the alpha server.)\n #\n # Warning: Allocating a public ID means that the /var/www and /var/mail directories become\n # special. Do not create these directories unless you intend for them to serve their respective\n # purposes.\n\n httpGet @1 (url: Text) -> (mimeType :Text, content :Data);\n # Perform a simple HTTP GET request, returning the content. Note that this hack is especially\n # temporary because it allows apps to trivially leak data. Longer-term, we want the user to\n # explicitly approve communications with external servers. However, since we don't have the\n # infrastrucutre for that yet, and we really want an RSS reader on Sandstorm, we're temporarily\n # adding this. As of this writing, it's possible to issue arbitrary HTTP requests from the client\n # side anyway.\n #\n # This interface is very limited currently -- e.g. it does not support arbitrary headers, POSTs,\n # etc. If you need any of these things, talk to the Sandstorm developers and we'll consider\n # adding some more hacks, but, again, this will all go away once the Powerbox is implemented.\n\n getUserAddress @2 () -> Email.EmailAddress;\n # Returns the address of the owner of the grain.\n\n obsoleteGenerateApiToken @3 (petname :Text, userInfo :Identity.UserInfo, expires :UInt64 = 0)\n -> (token :Text, endpointUrl :Text, tokenId :Text);\n obsoleteListApiTokens @4 () -> (tokens :List(TokenInfo));\n obsoleteRevokeApiToken @5 (tokenId :Text);\n # OBSOLETE. Apps that need to present API tokens to users should use offer templates.\n\n getUiViewForEndpoint @8 (url :Text) -> (view :Grain.UiView);\n # There are 3 cases here that are seamlessly handled by the platform\n # 1. If the URL is a local webkey, return a wrapped version of the UiView that respects user\n # permissions\n # 2. If the URL is a remote webkey (i.e. a different Sandstorm server), set up an ApiSession\n # that sends the Authorization header correctly. We wrap it in a UiVew so that this is seamless.\n # Some day, we'll connect via Cap'n Proto instead, and actually return the remote UiView\n # verbatim.\n # 3. If the URL is not a webkey at all, wrap it the same as #2, but don't send an Authorization\n # header.\n # If the url is a webkey, then your url must not contain a path.\n\n struct TokenInfo {\n tokenId @0 :Text;\n petname @1 :Text;\n userInfo @2 :Identity.UserInfo;\n }\n\n obsoleteGetIpNetwork @6 () -> (network: Ip.IpNetwork);\n obsoleteGetIpInterface @7 () -> (interface: Ip.IpInterface);\n # OBSOLETE. Apps that need IpNetwork or IpInterface should use the powerbox.\n}\n\ninterface HackEmailSession @0xc3b5ced7344b04a6 extends(Grain.UiSession, Email.EmailSendPort) {\n # UiView.newSession() may be called with this type as the session type in order to deliver\n # SMTP instead of HTTP requests. Of course, this doesn't actually implement a UI at all; it is\n # abusing the UI session API only because the correct way to open non-UI communications\n # channels -- i.e. persistent capabilities and Powerbox interactions -- is not implemented.\n}\n",
"identity-impl.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xacf10e4407376d3f;\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Identity = import \"identity.capnp\";\nusing SystemPersistent = import \"supervisor.capnp\".SystemPersistent;\n\ninterface PersistentIdentity extends (Identity.Identity, SystemPersistent) {}\n",
"sandstorm-http-bridge-internal.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xf963cc483d8f9e3a;\n# This file defines some types used internally by sandstorm-http-bridge. App developers need not\n# concern themselves with this code.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\nusing Identity = import \"identity.capnp\";\nusing WebSession = import \"web-session.capnp\".WebSession;\nusing ApiSession = import \"api-session.capnp\".ApiSession;\nusing AppPersistent = import \"grain.capnp\".AppPersistent;\n\nstruct BridgeObjectId {\n # The object ID format used by sandstorm-http-bridge.\n #\n # Recall that Sandstorm obfuscates object IDs automatically, such that clients cannot see the\n # contents and the app can trust that the ID passed from Sandstorm is authentic. Hence, we can\n # put all the metadata we need directly in this structure and let Sandstorm store it.\n\n union {\n application @0 :AnyPointer;\n # The object ID is in a format understood by the application, not by http-bridge.\n #\n # This is here to allow http-bridge-based applications to implement some APIs directly in\n # Cap'n Proto, or to transition entirely to the native API eventually while retaining backwards\n # compatibility.\n\n httpApi @1 :HttpApi;\n # An HTTP API, as defined using `BridgeConfig.PowerboxApi` (see `package.capnp`).\n }\n\n struct HttpApi {\n name @0 :Text;\n path @1 :Text;\n permissions @2 :Identity.PermissionSet;\n\n identityId @3 :Data;\n # Identity ID of the user who made the powerbox choice.\n #\n # TODO(someday): restore() should provide identity information so that we don't need this.\n }\n}\n\ninterface BridgeHttpSession extends(ApiSession, AppPersistent(BridgeObjectId)) {}\n\nconst bridgeRequestSessionHtml :Text = embed \"sandstorm-http-bridge-request.html\";\n",
"supervisor.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xc7205d6d32c7b040;\n# This file contains interfaces defining communication between a Sandstorm grain supervisor and\n# other components of the system. These interfaces are NOT used by Sandstorm applications.\n\n$import \"/capnp/c++.capnp\".namespace(\"sandstorm\");\n\nusing Util = import \"util.capnp\";\nusing Grain = import \"grain.capnp\";\nusing Persistent = import \"/capnp/persistent.capnp\".Persistent;\nusing Activity = import \"activity.capnp\";\nusing Identity = import \"identity.capnp\";\n\ninterface Supervisor {\n # Default capability exported by the supervisor process.\n\n getMainView @0 () -> (view :Grain.UiView);\n # Get the grain's main UiView.\n\n keepAlive @1 (core :SandstormCore);\n # Must call periodically to prevent supervisor from killing itself off. Call at least once\n # per minute.\n #\n # `core` may be null. If not null, then it is a new copy of the SandstormCore capability which\n # should replace the old one. This allows the grain to recover if the original SandstormCore\n # becomes disconnected.\n #\n # TODO(reliability): Passing `core` here is an ugly hack. The supervisor really needs a way to\n # proactively reconnect.\n\n syncStorage @8 ();\n # Calls syncfs() on /var.\n\n shutdown @2 ();\n # Shut down the grain immediately. Useful e.g. when upgrading to a newer app version. This\n # call will never return successfully because the process kills itself.\n\n obsoleteGetGrainSize @3 () -> (size :UInt64);\n obsoleteGetGrainSizeWhenDifferent @4 (oldSize :UInt64) -> (size :UInt64);\n # OBSOLETE: We used to pull the grain size from the supervisor. Now the supervisor pushes the\n # size through SandstormCore.\n\n restore @5 (ref :SupervisorObjectId, obsolete :List(MembraneRequirement), parentToken :Data)\n -> (cap :Capability);\n # Wraps `MainView.restore()`. Can also restore capabilities hosted by the supervisor.\n #\n # `obsolete` will always be an empty list. (Sandstorm will call `addRequirements()` immediately\n # after restore() if needed. Passing the list to restore() was removed because the supervisor\n # has no way of observing whether the requirements are still valid. `addRequirements()` provides\n # a mechanism for this.)\n #\n # `parentToken` is the API token restored to get this capability. The receiver will want to keep\n # this in memory in order to pass to `SandstormCore.makeChildToken()` later, if the live\n # capability is saved again.\n\n drop @6 (ref :SupervisorObjectId);\n # Wraps `MainView.drop()`. Can also drop capabilities hosted by the supervisor.\n\n watchLog @7 (backlogAmount :UInt64, stream :Util.ByteStream) -> (handle :Util.Handle);\n # Write the last `backlogAmount` bytes of the grain's debug log to `stream`, and then watch the\n # log for changes, writing them to `stream` as they happen, until `handle` is dropped.\n\n enum WwwFileStatus {\n file @0;\n directory @1;\n notFound @2;\n }\n\n getWwwFileHack @9 (path :Text, stream :Util.ByteStream) -> (status :WwwFileStatus);\n # Reads a file from under the grain's \"/var/www\" directory. If the path refers to a regular\n # file, the contents are written to `stream`, and `status` is returned as `file`. If the path\n # refers to a directory or is not found, then `stream` is NOT called at all and the method\n # returns the corresponding status.\n #\n # Note that if a Supervisor capability is obtained and used only for `getWwwFileHack()` -- i.e.\n # `getMainView()` and `restore()` are not called -- then the supervisor will not actually start\n # the application.\n #\n # This method is a temporary hack designed so that Sandstorm's front-end can implement web\n # publishing -- as defined by HackSessionContext -- without digging directly into the grain's\n # storage on-disk. Eventually, this mechanism for web publishing will be eliminated entirely\n # and replaced with a driver and powerbox interactions.\n}\n\ninterface SandstormCore {\n # When the front-end connects to a Sandstorm supervisor, the front-end exports a SandstormCore\n # capability as the default capability on the connection. This SandstormCore instance is specific\n # to the supervisor's grain; e.g. the grain ID is used to enforce ownership restrictions in\n # `restore()` and to fill out the `grainId` field in the `ApiTokens` table in calls to\n # `wrapSaved()`.\n #\n # If the front-end disconnects, this probably means that it is restarting. It will connect again\n # after restart. In the meantime, the supervisor should queue any RPCs to this interface and\n # retry them after the front-end has reconnected.\n\n restore @0 (token :Data) -> (cap :Capability);\n # Restores an API token to a live capability. Fails if this grain is not the token's owner\n # (including if the ref has no owner).\n\n claimRequest @6 (requestToken :Text, requiredPermissions :Identity.PermissionSet)\n -> (cap :Capability);\n # Restores a client powerbox request token to a live capability, which can then be saved to get\n # a proper sturdyref.\n #\n # `requiredPermissions` has the same meaning as in SandstormApi.claimRequest(). Note that the\n # callee will not only check these requirements, but will automatically ensure that the returned\n # capability has an appropriate `MembraneRequirement` applied; the caller need not concern\n # itself with this.\n\n drop @3 (token :Data);\n # Deletes the corresponding API token. See `MainView.drop()` for discussion of dropping.\n\n makeToken @1 (ref :SupervisorObjectId, owner :ApiTokenOwner,\n requirements :List(MembraneRequirement)) -> (token :Data);\n # When the supervisor receives a save() request for a capability hosted by the app, it first\n # calls save() on the underlying capability to get an AppObjectId, then calls makeToken() to\n # convert this to a token which it can then return.\n #\n # Similarly, when the supervisor receives a save() request for a capability it itself hosts\n # (outside of the app), it constructs the appropriate `SupervisorObjectId` and passes it to\n # `makeToken()`.\n #\n # If any of the conditions listed in `requirements` become untrue, the returned token will be\n # disabled (cannot be restored).\n\n makeChildToken @5 (parent :Data, owner :ApiTokenOwner,\n requirements :List(MembraneRequirement)) -> (token :Data);\n # Given a token (probably originally passed to `Supervisor.restore()`), create a new token\n # pointing to the same capability, where if the original token is revoked, the new token is\n # also transitively revoked.\n\n getOwnerNotificationTarget @2 () -> (owner :Activity.NotificationTarget);\n # Get the notification target to use for notifications relating to the grain itself, e.g.\n # presence of wake locks.\n\n obsoleteCheckRequirements @4 ();\n # OBSOLETE: This was never implemented, and wouldn't have worked correctly as specified.\n # (It involved an RPC that hangs until something happens, which implicitly requires the ability\n # for the server to receive call cancellations, which doesn't exist in node-capnp.)\n\n backgroundActivity @7 (event :Activity.ActivityEvent);\n # Implements SandstormApi.backgroundActivity().\n\n reportGrainSize @8 (bytes :UInt64);\n # Reports the current disk storage usage of the grain. The supervisor monitors storage usage\n # while the grain runs and calls this method periodically. In order to avoid unnecessary traffic,\n # the supervisor may choose not to report insignificant changes.\n\n getIdentityId @9 (identity :Identity.Identity) -> (id :Data);\n # Gets the ID of the identity, as it would appear in UserInfo.identityId.\n}\n\nstruct MembraneRequirement {\n # Indicates some condition which, if it becomes untrue, will cause a membrane to be revoked.\n\n union {\n tokenValid @0 :Text;\n # This token is valid only as long as some *other* token is also still valid. `tokenValid`\n # specifies the `_id` of the other ApiToken.\n\n permissionsHeld :group {\n # This token is valid only as long as some vertex in the sharing graph holds some specified\n # set of permissions on some specified grain.\n\n union {\n accountId @5 :Text;\n # The permissions must be held by the user account with this ID.\n\n tokenId @6: Text;\n # The permissions must be held by anyone who bears the token with this ID.\n }\n\n grainId @2 :Text;\n # The grain on which the permissions must be held.\n\n permissions @3 :Identity.PermissionSet;\n # The permissions that must be held.\n\n userId @1 :Text;\n # Deprecated. See `identityId`.\n }\n\n userIsAdmin @4 :Text;\n # The capability is valid only as long as the given user is an administrator.\n }\n}\n\ninterface SystemPersistent extends(Persistent(Data, ApiTokenOwner)) {\n # The specialization of `Persistent` used in the \"Sandstorm internal\" realm, which is the realm\n # used by Sandstorm system components talking to each other. This realm is NOT seen by Sandstorm\n # applications; each grain is its own realm, and the Supervisor performs translations\n # transparently.\n #\n # In the Sandstorm internal realm, the type of SturdyRefs themselves is simply `Data`, where the\n # data is an API token. The SHA-256 hash of this token is an ID into the `ApiTokens` collection.\n # The token itself is arbitrary random bytes, not ASCII text (this differs from API tokens\n # created for the purpose of HTTP APIs).\n\n interface RevocationObserver {\n dropWhenRevoked @0 (handle :Util.Handle);\n # Holds on to `handle` until revocation occurs, then drops it.\n }\n\n addRequirements @0 (requirements :List(MembraneRequirement), observer :RevocationObserver)\n -> (cap :SystemPersistent);\n # Returns a new version of this same capability with the given requirements added to the\n # conditions under which the capability may be revoked. Usually, the caller then calls `save()`\n # on the new capability.\n #\n # `observer` is an object that watches for the requirements to become invalid. When that happens,\n # it drops any handles registered with it. `observer` itself should be held by `cap`, such that\n # dropping `cap` causes `observer` to be dropped transitively (this allows the observer to stop\n # observing when no longer needed).\n #\n # This call is actually supported on *all* capabilities that are proxied through the supervisor,\n # not just persistent ones.\n #\n # TODO(someday): This method should be supported by all capabilities within the Sansdtorm realm,\n # by having every endpoint implement the appropriate membrane. SystemPersistent should probably\n # be renamed and split from `Persistent` -- the inheritance heirarchy can be adjusted without\n # breaking compatibility.\n}\n\ninterface PersistentHandle extends(SystemPersistent, Util.Handle) {}\n\ninterface PersistentOngoingNotification extends(SystemPersistent, Activity.OngoingNotification) {}\n\nstruct DenormalizedGrainMetadata {\n # The metadata that we need to present contextual information for shared grains (in particular,\n # information about the app providing that grain, like icon and title).\n\n appTitle @0 :Util.LocalizedText;\n # A copy of the app name for the corresponding UIView for presentation in the grain list.\n\n union {\n icon :group {\n format @1 :Text;\n # Icon asset format, if present. One of \"png\" or \"svg\"\n\n assetId @2 :Text;\n # The asset ID associated with the grain-size icon for this token\n\n assetId2xDpi @3 :Text;\n # If present, the asset ID for the equivalent asset as assetId at twice-resolution\n }\n appId @4 :Text;\n # App ID, needed to generate a favicon if no icon is provided.\n }\n}\n\nstruct ApiTokenOwner {\n # Defines who is permitted to use a particular API token.\n\n union {\n webkey @0 :Void;\n # This API token is for use on \"the web\", with no specific owner. This is the kind of token\n # that you get when you use the Sandstorm UI to create a webkey.\n #\n # Note that a webkey CANNOT be directly restored by an app, since this would break confinement\n # (an app could be shipped with a webkey baked in). Instead, the app must make a powerbox\n # request, and the user may paste in a webkey there. Apps can only restore tokens explicitly\n # owned by them.\n #\n # (HackSessionContext actually allows webkeys to be exchanged for live capabilities, but this\n # is temporary until the powerbox is built.)\n\n grain :group {\n # Owned by a local grain.\n\n grainId @1 :Text;\n # Grain ID owning the ref.\n\n saveLabel @2 :Util.LocalizedText;\n # As passed to `save()` in Sandstorm's Persistent interface.\n\n introducerIdentity @9 :Text;\n # Obsolete. See `clientPowerboxRequest.introducerIdentity`.\n\n introducerUser @5 :Text;\n # Obsolete. See `clientPowerboxRequest.introducerIdentity`.\n }\n\n clientPowerboxRequest :group {\n # Owned by a local grain, but only halfway through a client-side powerbox request flow.\n # The token will be automatically deleted after a short amount of time. Before then, the\n # grain must call `SandstormApi.claimRequest()` to get a proper sturdyref.\n\n sessionId @15 :Text;\n # The ID of the session that created this token.\n\n grainId @13 :Text;\n # Obsolete. (The owning grain is the one associated with sessionId.)\n\n introducerIdentity @14 :Text;\n # Obsolete. (The introducer identity can be derived from sessionId instead.)\n }\n\n clientPowerboxOffer :group {\n # When a grain calls `SessionContext.offer(cap)` and the powerbox decides to present the\n # capability as a webkey, we push the offered capability to the client through the\n # `Sessions` collection as a token with `clientPowerboxOffer` owner. The token will be\n # automatically deleted after a short amount of time, before which the client must call the\n # \"acceptPowerboxOffer\" Meteor method to convert the token into a durable webkey.\n #\n # This variant exists to avoid the need to write a durable webkey into the database, where,\n # due to journaling, it would remain readable forever. In principle, the extra step entailed\n # by `clientPowerboxOffer` is not strictly necessary, and we should be able to directly\n # return the webkey without writing anything to the database. That approach, however, is a\n # bit tricky in the case where Sandstorm is running multiple frontends.\n\n sessionId @17 :Text;\n # The ID of the session that is allowed to accept this offer.\n }\n\n internet @3 :AnyPointer;\n # An owner on the public internet, who used the Cap'n Proto public internet transport to call\n # `save()` and expects it to authenticate them on later `restore()`.\n #\n # TODO(someday): Change `AnyPointer` to the type for public internet owners, once the public\n # internet Cap'n Proto protocol is defined. (Or, do we want Sandstorm nodes to be able to\n # nested within broader networks that aren't the internet? Hmm.)\n\n frontend @4 :Void;\n # Owned by the front-end, i.e. stored in its Mongo database.\n\n user :group {\n # Owned by a user's identity. If the token represents a UiView, then it will show up in this\n # user's grain list.\n\n accountId @18 :Text;\n # The account that is allowed to restore this token.\n\n identityId @10 :Text;\n # The identity ID used to identify this user to the app, in the context of this grain. The\n # app does not receive the user's account ID because this could allow unwanted correlation\n # of users between grains, and becaues grains may transfer between Sandstorm instances where\n # account IDs may differ.\n\n title @7 :Text;\n # Title as chosen by the user, or as copied from the sharer.\n\n # Fields below this line are not actually allowed to be passed to save(), but are added\n # internally.\n\n denormalizedGrainMetadata @8 :DenormalizedGrainMetadata;\n # Information needed to show the user an app title and icon in the grain list.\n\n userId @6 :Text;\n # Deprecated. See `identityId`.\n\n upstreamTitle @11 :Text;\n # Title as chosen by the grain owner. This field is directly updated whenever the grain owner\n # changes the title. As an optimization, this field is omitted if the value would be\n # identical to `title`.\n\n renamed @12 :Bool;\n # True if the user has explicitly renamed the grain to differ from the owner's title.\n # Otherwise, `title` is a copy of either the current or previous value of `upstreamTitle`.\n\n seenAllActivity @16 :Bool;\n # True if the user has viewed the grain since the last activity event occurred.\n }\n }\n}\n\nstruct SupervisorObjectId(AppObjectId) {\n # Refers to some persistent object which the Supervisor for a particular grain knows how to\n # restore.\n\n union {\n appRef @0 :AppObjectId;\n # A reference restorable by the app.\n\n wakeLockNotification @1 :UInt32;\n # This refers to an OngoingNotification for a wake lock. Note that although the app itself\n # implements an `OngoingNotification`, the supervisor wraps it in order to detect the `cancel`\n # call.\n }\n}\n",
"web-session.capnp": "# Sandstorm - Personal Cloud Sandbox\n# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors\n# All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n@0xa8cb0f2f1a756b32;\n\nusing Cxx = import \"/capnp/c++.capnp\";\n$Cxx.namespace(\"sandstorm\");\n\nusing Grain = import \"grain.capnp\";\nusing Util = import \"util.capnp\";\n\nstruct HttpStatusDescriptor {\n id @0 :UInt16;\n title @1 :Text;\n}\nannotation httpStatus @0xaf480a0c6cab8887 (enumerant) :HttpStatusDescriptor;\nconst httpStatusAnnotationId :UInt64 = 0xaf480a0c6cab8887;\n\ninterface WebSession @0xa50711a14d35a8ce extends(Grain.UiSession) {\n # A UI session based on the web platform. The user's browser communicates to the server through\n # HTTP requests.\n #\n # Many of the details of HTTP are implemented by the platform and thus not exposed here. For\n # example, the platform may automatically set last-modified based on the last time the\n # application's storage was written and may automatically implement etags based on hashing the\n # content.\n\n struct Params {\n # Startup params for web sessions. See `UiView.newSession()`.\n\n basePath @0 :Text;\n # HTTP URL of the application's root directory as seen by this user, e.g.\n # \"https://ioa5fiu34sm4w.example.com/i7efqesOldepw\". Never includes the trailing '/'. Useful\n # for constructing intra-app link URLs, although in general you should try to use relative URLs\n # whenever possible. Note that the URL can change from session to session and from user to\n # user, hence it is only valid for the current session.\n\n userAgent @1 :Text;\n acceptableLanguages @2 :List(Text);\n # Content of User-Agent and Accept-Language headers. The platform will start a new session if\n # any of these change.\n # TODO(soon): Support utility factor (e.g. \";q=0.7\").\n }\n\n get @0 (path :Text, context :Context, ignoreBody :Bool) -> Response;\n # GET or HEAD request.\n #\n # If `ignoreBody` is true, then the caller intends to ignore any content body returned. The\n # caller may choose to return an empty body. (This is used e.g. for HEAD requests.)\n\n post @1 (path :Text, content :PostContent, context :Context) -> Response;\n put @3 (path :Text, content :PutContent, context :Context) -> Response;\n delete @4 (path :Text, context :Context) -> Response;\n patch @17 (path :Text, content :PostContent, context :Context) -> Response;\n\n postStreaming @5 (path :Text, mimeType :Text, context :Context, encoding :Text)\n -> (stream :RequestStream);\n putStreaming @6 (path :Text, mimeType :Text, context :Context, encoding :Text)\n -> (stream :RequestStream);\n # Streaming post/put requests, useful when the input is large. If these throw `unimplemented`\n # exceptions, the caller should fall back to regular post() / put() on the assumption that the\n # app doesn't implement streaming.\n #\n # The optional `encoding` field represents the Content-Encoding header.\n\n openWebSocket @2 (path :Text, context :Context,\n protocol :List(Text), clientStream :WebSocketStream)\n -> (protocol :List(Text), serverStream :WebSocketStream);\n # Open a new WebSocket. `protocol` corresponds to the `Sec-WebSocket-Protocol` header.\n # `clientStream` is the capability which will receive server -> client messages, while\n # serverStream represents client -> server.\n\n propfind @7 (path :Text, xmlContent :Text, depth :PropfindDepth, context :Context) -> Response;\n proppatch @8 (path :Text, xmlContent :Text, context :Context) -> Response;\n mkcol @9 (path :Text, content :PostContent, context :Context) -> Response;\n copy @10 (path :Text, destination :Text, noOverwrite :Bool,\n shallow :Bool, context :Context) -> Response;\n move @11 (path :Text, destination :Text, noOverwrite :Bool, context :Context) -> Response;\n lock @12 (path :Text, xmlContent :Text, shallow :Bool, context :Context) -> Response;\n unlock @13 (path :Text, lockToken :Text, context :Context) -> Response;\n acl @14 (path :Text, xmlContent :Text, context :Context) -> Response;\n report @15 (path :Text, content :PostContent, context :Context) -> Response;\n # WebDAV methods\n #\n # \"destination\" is a *path*, but *not* a URI -- the origin is stripped, and there is no leading\n # '/', just like with the `path` parameter.\n # \"shallow = true\" means \"Depth: 0\"\n # \"noOverwrite = true\" means \"Overwrite: F\"; note that this behaves a precondition -- if the\n # destination already exists then a preconditionFailed response is returned.\n #\n # (These boolean flags were intentionally chosen so that the spec-defined default values are\n # false.)\n\n options @16 (path :Text, context :Context) -> Options;\n # OPTIONS request.\n\n struct Context {\n # Additional per-request context.\n\n cookies @0 :List(Util.KeyValue);\n\n responseStream @1 :Util.ByteStream;\n # Stream to which the app can optionally write the response body. This is only actually\n # used in the case of a `content` response where the `body` union is set to `stream`. In that\n # case, after returning from the HTTP method, the app begins writing bytes to `responseStream`.\n #\n # Since it's not guaranteed that `responseStream` will be used, and because it would be\n # confusing to start receiving `write()` calls on it before receiving the HTTP response,\n # callers should typically initialize this field with a promise. When the response indicates\n # streaming, the caller can then resolve that promise and start receiving the content.\n #\n # Callers are required to provide this capability; apps need not handle it being null.\n\n accept @2 :List(AcceptedType);\n # This corresponds to the Accept header\n\n acceptEncoding @9 :List(AcceptedEncoding);\n # This corresponds to the Accept-Encoding header\n\n eTagPrecondition :union {\n none @4 :Void; # No precondition.\n exists @5 :Void; # If-Match: *\n doesntExist @8 :Void; # If-None-Match: *\n matchesOneOf @6 :List(ETag); # If-Match\n matchesNoneOf @7 :List(ETag); # If-None-Match\n }\n\n additionalHeaders @3 :List(Header);\n # Additional headers present in the request. Only whitelisted headers are\n # permitted.\n\n struct Header {\n name @0 :Text; # lower-cased name\n value @1 :Text;\n }\n\n const headerWhitelist :List(Text) = [\n # Non-standard request headers which are whitelisted for backwards-compatibility\n # purposes. This whitelist exists to help avoid the need to modify code originally written\n # without Sandstorm in mind -- especially to avoid modifying client apps. Feel free\n # to send us pull requests adding additional headers.\n # Values in this list that end with '*' whitelist a prefix.\n\n \"x-sandstorm-app-*\", # For new headers introduced by Sandstorm apps.\n\n \"oc-total-length\", # Owncloud client\n \"oc-chunk-size\", # Owncloud client\n \"x-oc-mtime\", # Owncloud client\n \"oc-fileid\", # Owncloud client\n \"oc-chunked\", # Owncloud client\n \"x-hgarg-*\", # Mercurial client\n \"x-phabricator-*\", # Phabricator\n \"x-requested-with\", # JQuery header used by Rails and other frameworks\n ];\n }\n\n struct PostContent {\n # TODO(apibump): Rename this to just `Content` or maybe `RequestContent`.\n\n mimeType @0 :Text;\n content @1 :Data;\n encoding @2 :Text; # Content-Encoding header (optional).\n }\n\n struct PutContent {\n # TODO(apibump): Remove this and replace it with `PostContent` (renamed to `Content`).\n\n mimeType @0 :Text;\n content @1 :Data;\n encoding @2 :Text; # Content-Encoding header (optional).\n }\n\n struct ETag {\n value @0 :Text; # does not include quotes\n weak @1 :Bool;\n # denotes that the resource may not be byte-for-byte identical, but is\n # semantically equivalent\n }\n\n struct Cookie {\n # Strings here must not contain ';' nor ','. Also, `name` cannot contain '='.\n\n name @0 :Text;\n value @1 :Text;\n expires :union {\n none @2 :Void;\n absolute @3 :Int64; # Unix timestamp.\n relative @4 :UInt64; # Seconds relative to time of receipt.\n }\n httpOnly @5 :Bool;\n path @6 :Text;\n\n # We don't include \"secure\" because the platform automatically forces all cookies to be secure.\n }\n\n struct AcceptedType {\n # In the accept header, there is a list of these elements.\n # The qValue is optional and defaults to 1.\n #\n # For example, the Accept header with value 'text/javascript; q=0.01' would have a mimeType of\n # \"text/javascript\" and a qValue of .01.\n mimeType @0 :Text;\n qValue @1 :Float32 = 1;\n }\n\n struct AcceptedEncoding {\n # The Accept-Encoding header contains a list of valid content codings.\n # Each content coding could be \"*\", indicating an arbitrary encoding.\n # Each content coding comes with a qValue, defaulting to 1.\n # For example, gzip;q=0.5 indicates the \"gzip\" coding with qValue \"0.5\"\n\n contentCoding @0 :Text;\n qValue @1 :Float32 = 1;\n }\n\n struct Response {\n setCookies @0 :List(Cookie);\n cachePolicy @16 :CachePolicy;\n\n enum SuccessCode {\n # 2xx-level status codes that we allow an app to return.\n #\n # We do not permit arbitrary status codes because some have semantic meaning that could\n # cause browsers to do things we don't expect. An unrecognized status code coming from a\n # sandboxed HTTP server will translate to 500, except for unrecognized 4xx codes which will\n # translate to 400.\n #\n # It's unclear how useful it is to even allow 201 or 202, but since a browser will certainly\n # treat them as equivalent to 200, we allow them.\n\n ok @0 $httpStatus(id = 200, title = \"OK\");\n created @1 $httpStatus(id = 201, title = \"Created\");\n accepted @2 $httpStatus(id = 202, title = \"Accepted\");\n\n noContent @3 $httpStatus(id = 204, title = \"No Content\");\n partialContent @4 $httpStatus(id = 206, title = \"Partial Content\");\n multiStatus @5 $httpStatus(id = 207, title = \"Multi-Status\");\n\n # This seems to fit better here than in the 3xx range\n notModified @6 $httpStatus(id = 304, title = \"Not Modified\");\n\n # Not applicable:\n # 203 Non-Authoritative Information: Only applicable to proxies?\n # 205 Reset Content: Like 204, but even stranger.\n # Others: Not standard.\n }\n\n enum ClientErrorCode {\n # 4xx-level status codes that we allow an app to return.\n #\n # It's unclear whether status codes other than 400, 403, and 404 have any real utility;\n # arguably, all client errors should just use code 400 with an accompanying human-readable\n # error description. But, since browsers presumably treat them all equivalently to 400, it\n # seems harmless enough to allow them through.\n #\n # An unrecognized 4xx error code coming from a sandboxed HTTP server will translate to 400.\n\n badRequest @0 $httpStatus(id = 400, title = \"Bad Request\");\n forbidden @1 $httpStatus(id = 403, title = \"Forbidden\");\n notFound @2 $httpStatus(id = 404, title = \"Not Found\");\n methodNotAllowed @3 $httpStatus(id = 405, title = \"Method Not Allowed\");\n notAcceptable @4 $httpStatus(id = 406, title = \"Not Acceptable\");\n conflict @5 $httpStatus(id = 409, title = \"Conflict\");\n gone @6 $httpStatus(id = 410, title = \"Gone\");\n preconditionFailed @11 $httpStatus(id = 412, title = \"Precondition Failed\");\n requestEntityTooLarge @7 $httpStatus(id = 413, title = \"Request Entity Too Large\");\n requestUriTooLong @8 $httpStatus(id = 414, title = \"Request-URI Too Long\");\n unsupportedMediaType @9 $httpStatus(id = 415, title = \"Unsupported Media Type\");\n imATeapot @10 $httpStatus(id = 418, title = \"I'm a teapot\");\n unprocessableEntity @12 $httpStatus(id = 422, title = \"Unprocessable Entity\");\n\n # Not applicable:\n # 401 Unauthorized: We don't do HTTP authentication.\n # 402 Payment Required: LOL\n # 407 Proxy Authentication Required: Not a proxy.\n # 408 Request Timeout: Not possible; the entire request is provided with the call.\n # 411 Length Required: Request is framed using Cap'n Proto.\n # 412 Precondition Failed: If we implement preconditions, they should be handled\n # separately from errors.\n # 416 Requested Range Not Satisfiable: Ranges not implemented (might be later).\n # 417 Expectation Failed: Like 412.\n # Others: Not standard.\n }\n\n union {\n content :group {\n # Return content (status code 200, or perhaps 201 or 202).\n\n statusCode @10 :SuccessCode;\n\n encoding @2 :Text; # Content-Encoding header (optional).\n language @3 :Text; # Content-Language header (optional).\n mimeType @4 :Text; # Content-Type header.\n\n eTag @17 :ETag;\n # Optional entity tag for this content. This can be used to express preconditions on future\n # requests, useful for implementing, for example, cache validation (on GETs) and optimistic\n # concurrency (on PUTs). See `eTagPrecondition` in `WebSession.Context`.\n\n body :union {\n bytes @5 :Data;\n\n stream @6 :Util.Handle;\n # Indicates that the content will be streamed to the `responseStream` offered in the\n # call's `Context`. The caller may cancel the stream by dropping the Handle.\n #\n # Note that to prevent a grain from being shut down in the middle of a large download,\n # it is necessary to call ping() on this handle every 60 seconds.\n }\n\n disposition :union {\n normal @13 :Void;\n download @14 :Text; # Prompt user to save as given file name.\n }\n }\n\n noContent :group {\n # Return successful, but with no content (status codes 204 and 205)\n\n shouldResetForm @15 :Bool;\n # If this is the response to a form submission, should the form be reset to empty?\n # Distinguishes between HTTP response 204 (False) and 205 (True)\n\n eTag @19 :ETag;\n # Optional entity tag header. Server can send this in a response to a modifying request\n # to indicate for example the new version of the modified resource.\n }\n\n preconditionFailed :group {\n # One of the preconditions specified in the request context was not met.\n #\n # If the request was a GET or HEAD and the precodition was If-None-Match, then this response\n # corresponds to HTTP 304 \"Not Modified\". In all other ctases, this response corresponds to\n # HTTP 412 \"Precondition Failed\". (We unify these two HTTP status codes because they really\n # mean the same thing and should be implemented by the same code.)\n\n matchingETag @18 :ETag;\n # If the precondition failed because the etag matched a tag specified in `matchesNoneOf`,\n # this is the tag that it matched. For other types of preconditions, this is null.\n #\n # (This is in particular used for GET requests where the result is \"304 not modified\".)\n }\n\n redirect :group {\n # Redirect to the given URL.\n #\n # Note that 3xx-level HTTP responses have specific semantic meanings, therefore we actually\n # represent that meaning here rather than having a 3xx status code enum. `redirect`\n # covers only 301, 302 (treated as 303), 303, 307, and 308. Other 3xx status codes\n # need to be handled in a completely different way, since they are not redirects.\n\n isPermanent @1 :Bool;\n # Is this a permanent (cacheable) redirect?\n\n switchToGet @12 :Bool;\n # Should the user-agent change the method to GET when accessing the new location?\n # Otherwise, it should repeat the same method as was used for this request.\n\n location @11 :Text;\n # New URL to which to redirect.\n #\n # TODO(security): Supervisor should prohibit locations outside the app's host.\n }\n\n clientError :group {\n # HTTP 4xx-level error. The platform will generate a suitable error page.\n\n statusCode @7 :ClientErrorCode;\n\n descriptionHtml @8 :Text;\n # Optional extended description of the error, as an HTML document.\n #\n # If the response is not text/html, use nonHtmlContent.\n #\n # TODO(apibump): Get rid of this and use only nonHtmlContent.\n\n nonHtmlBody @21 :ErrorBody;\n # Response body, of a type that isn't text/html. If present, descriptionHtml should be\n # ignored. However, older programs only know about descriptionHtml.\n }\n\n serverError :group {\n # HTTP 5xx-level error. The platform will generate a suitable error page.\n #\n # We don't support status codes here because basically none of them are applicable anyway\n # except 500.\n\n descriptionHtml @9 :Text;\n # Optional extended description of the error, as an HTML document.\n #\n # TODO(apibump): Get rid of this and use only nonHtmlContent.\n\n nonHtmlBody @22 :ErrorBody;\n # Response body, of a type that isn't text/html. If present, descriptionHtml should be\n # ignored. However, older programs only know about descriptionHtml.\n }\n\n # TODO(someday): Return blob directly from storage, so data doesn't have to stream through\n # the app?\n }\n\n additionalHeaders @20 :List(Header);\n # Additional headers present in the reponse. Only whitelisted headers are\n # permitted.\n\n struct Header {\n name @0 :Text; # lower-cased name\n value @1 :Text;\n }\n\n struct ErrorBody {\n data @0 :Data;\n encoding @1 :Text; # Content-Encoding header (optional).\n language @2 :Text; # Content-Language header (optional).\n mimeType @3 :Text; # Content-Type header.\n }\n\n const headerWhitelist :List(Text) = [\n # Non-standard response headers which are whitelisted for backwards-compatibility\n # purposes. This whitelist exists to help avoid the need to modify code originally written\n # without Sandstorm in mind -- especially to avoid modifying client apps.\n # Feel free to send us pull requests adding additional headers.\n # Values in this list that end with '*' whitelist a prefix.\n\n \"x-sandstorm-app-*\", # For new headers introduced by Sandstorm apps.\n\n \"x-oc-mtime\", # Owncloud protocol\n ];\n\n }\n\n interface RequestStream extends(Util.ByteStream) {\n # A streaming request. The request body is streamed in via the methods of ByteStream.\n\n getResponse @0 () -> Response;\n # Get the final HTTP response. The caller should call this immediately, before it has actually\n # written the request data.\n #\n # The method is allowed to return early, e.g. in order to start streaming the response while\n # the request is still uploading. Thus, full-duplex streaming is supported. This is useful in\n # some obscure cases. For example, an HTTP server that just encrypts the request could do so\n # by streaming back the response as the request comes in so that it does not need to buffer the\n # whole thing.\n #\n # If the response is completely transmitted before the request finishes uploading, the caller\n # may cancel the upload stream by simply dropping the RequestStream object (without calling\n # done()). Note that in the case of a streaming response, \"completely transmitted\" means that\n # the response stream's done() method has been called, or the response stream itself has been\n # dropped.\n }\n\n interface WebSocketStream {\n sendBytes @0 (message :Data);\n # Send some bytes. WARNING: At present, we just send the raw bytes of the WebSocket protocol.\n # In the future, this will be replaced with a `sendMessage()` method that sends one WebSocket\n # datagram at a time.\n #\n # TODO(apibump): Send whole WebSocket messages.\n }\n\n struct CachePolicy {\n enum Scope {\n # Defines the scope in which caching is allowed. For security reasons, the resource MUST NOT\n # be stored in a cache with a broader scope, even if it is never actually served from that\n # cache.\n\n none @0;\n # This resource must not be stored in any cache.\n\n perSession @1;\n # Caching is allowed on a per-session basis.\n\n perUser @2;\n # Caching is allowed on a per-user basis (across multiple sessions).\n\n perAppVersion @3;\n # Caching is allowed on a per-app-version basis (across all users). This is a\n # Sandstorm-specific notion.\n\n universal @4;\n # Caching is allowed universally, across all users and versions of the app.\n }\n\n withCheck @0 :Scope;\n # Within a cache serving this scope or a narrower scope, the resource may be stored in cache,\n # but if a non-negligible amount of time has gone by since the resource was last validated then\n # the client must check with the server that the resource hasn't changed (revalidate).\n #\n # \"A non-negligible amount of time\" means something on the order of the network latency between\n # the client and the server. For example, there is obviously no point in re-validating a cached\n # resource if it was last validated less than one network round trip ago. For optimization\n # reasons, we allow this to be expanded a bit -- something like a 15s timeout is OK. Ultimately\n # it is up to the infrastructure to decide, though; if an app is not OK with this, it should\n # specify `withCheck` = `none`.\n\n permanent @1 :Scope;\n # Within a cache serving this scope or a narrower scope, the resource may be assumed never to\n # change, and may be served directly from cache without checking with the server.\n #\n # Note that we do not allow specification of a cache duration other than \"forever\" because in\n # practice if the resource is mutable at all, you almost certainly don't know when it will next\n # change, and so setting a non-zero cache duration will lead to stale data bugs.\n\n variesOnCookie @2 :Bool;\n variesOnAccept @3 :Bool;\n # Indicates what inputs in `Context` would have caused a different response to be served.\n # If these are false and caching is enabled, it is assumed the resource is identical regardless\n # of these inputs.\n }\n\n struct Options {\n davClass1 @0 :Bool = false;\n davClass2 @1 :Bool = false;\n davClass3 @2 :Bool = false;\n davExtensions @3 :List(Text);\n }\n\n enum PropfindDepth {\n infinity @0 $Cxx.name(\"infinity_\"); # INFINITY is a macro in C\n zero @1;\n one @2;\n }\n\n # Request headers that we will probably add later:\n # * Caching:\n # * Cache-Control\n # * If-*\n # * Range requests:\n # * Range\n #\n # Request headers that could be added later, but don't seem terribly important:\n # * Accept\n # * Accept-Charset\n # * Accept-Encoding\n # * Content-MD5 (MD5 is dead; perhaps we could introduce a modern alternative)\n # * Date\n # * From\n # * Max-Forwards\n # * Warning\n # * Pragma\n #\n # Request headers which will NOT be added ever:\n # * Sandstorm handles authorization:\n # * Authorization\n # * Sandstorm defines cross-origin request permissions:\n # * Access-Control-Request-Headers\n # * Access-Control-Request-Method\n # * Origin\n # * Redundant or irrelevant to Cap'n Proto RPC:\n # * Connection\n # * Content-Length\n # * Expect\n # * Host\n # * Keep-Alive\n # * TE\n # * Trailer\n # * Transfer-Encoding\n # * Upgrade\n # * Apps should not have this information:\n # * Referer\n # * Via\n # * Proxy-*\n # * Sec-*\n # * Sandstorm already prevents illicit tracking technically; no need for policy:\n # * DNT\n\n # Response headers that we will probably add later:\n # * Caching:\n # * Age\n # * Cange-Control\n # * ETag\n # * Expires\n # * Last-Modified\n # * Vary (but Sandstorm will always add \"Authorization\")\n # * Range requests:\n # * Accept-Ranges\n # * Content-Range\n #\n # Response headers that could be added later, but don't seem terribly important:\n # * Allow\n # * Content-Location\n # * Content-MD5 - MD5 is dead; perhaps we could introduce a modern alternative.\n # * Content-Disposition (filename part only)\n # * Link\n # * Pragma\n # * Refresh\n # * Retry-After\n # * Server\n # * Via\n # * Warning\n #\n # Response headers which will NEVER be implemented:\n # * Sandstorm defines cross-origin request permissions:\n # * Access-Control-*\n # * Sandstorm uses these for sandboxing:\n # * Content-Security-Policy\n # * X-Frame-Options\n # * Redundant or irrelevant to Cap'n Proto RPC:\n # * Connection\n # * Content-Length - Redundant.\n # * Trailer\n # * Transfer-Encoding\n # * Upgrade\n # * These belong to the domain owner, not the app:\n # * Public-Key-Pins\n # * Strict-Transport-Security\n # * Sandstorm controls authentication:\n # * WWW-Authenticate\n # * Irrelevant to servers:\n # * Proxy-Authenticate\n}\n",
}