# Sandstorm - Personal Cloud Sandbox
# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

@0xeb014c0c3413cbfb;

$import "/capnp/c++.capnp".namespace("sandstorm");

using WebSession = import "web-session.capnp";
using IpAddress = import "ip.capnp".IpAddress;

interface ApiSession @0xc879e379c625cdc7 extends(WebSession.WebSession) {
  # A special case of WebSession but for APIs. It doesn't provide much other
  # than a unique type id that we can identify ApiSessions with

  struct Params {
    # Normally, we strip the remote address from requests, since most applications shouldn't need
    # it.  However, for those that benefit from it (like analytics), clients can opt into passing
    # their IP on to the backend by adding an "X-Sandstorm-Passthrough: address" header to their
    # request.  This would be a privacy leak for WebSession, since the grain can give the client
    # scripts which would send the header, but ApiSession requires a user action, so it's safe
    # here.
    remoteAddress @0 :IpAddress;
  }

  struct PowerboxTag {
    # A tag used for PowerboxDescriptors describing HTTP APIs. Such descriptors should typically
    # indicate `ApiSession` as the requested interface and use PowerboxTag to specify what API is
    # expected (so, the tag ID is ApiSession's ID, but the tag value is an ApiSession.PowerboxTag).
    #
    # Usually, this tag is used to request APIs implemented by internet services external to
    # Sandstorm. However, a Sandstorm grain may advertise itself as supporting a compatible API
    # to the Powerbox, and if so the Powerbox will allow the user to select that grain for such
    # requests. Note that publishing an `ApiSession` has nothing to do with `UiView` or Sandstorm's
    # normal HTTP API support.
    #
    # Requests of this type trigger the HTTP driver, such that the powerbox UI will display a
    # special flow for connecting to external web services. The Powerbox will also surface other
    # grains that advertise their ability to handle these requests under the usual matching rules.
    # This struct is carefully designed such that the usual Powerbox query rules make sense for
    # performing such queries.
    #
    # If you make a Powerbox request containing multiple PowerboxDescriptors describing HTTP APIs,
    # the HTTP driver will offer the user a choice among the options. This can make sense for, say,
    # allowing the user to choose from multiple popular servers implementing the same protocol, or
    # to choose whether or not to grant the app optional permissions (OAuth scopes). The HTTP
    # driver will return a capability with a descriptor matching one of the requested descriptors
    # which best-describes the user's choice.

    canonicalUrl @0 :Text;
    # The standard URL at which this service is found. Use this especially for traditional SaaS
    # services. For example, you might request "https://api.github.com" to request access to the
    # GitHub API.
    #
    # If you include a path in the URL, requests will automatically be prefixed with that path. You
    # should usually include enough path components to identify a specific product and version, but
    # usually not specific collection types within that product. For example, you would request the
    # Google Calendar API version 2 as "https://apidata.googleusercontent.com/caldav/v2". However,
    # you would not normally request "https://api.github.com/users" because "GitHub users" is not
    # considered a separate API but rather one part of the overall GitHub API. Note that
    # `canonicalUrl` should never end with a '/', because a '/' is added implicitly to separate
    # the API URL from the individual request's path.
    #
    # The HTTP driver will present `canonicalUrl` as a strong suggestion to the user. However, the
    # user is always allowed to substitute a different URL instead, causing requests to be
    # redirected to some other service. This is the user's choice. In cases where the app does not
    # trust the user, the app will need to defend itself against the possibility that the user
    # connects it to a malicious server.
    #
    # The Powerbox will also offer matches published by other grains using the usual query matching
    # rules. That is, a grain may advertise that it can handle queries for HTTP APIs with a
    # particular `canonicalUrl`, indicating that the grain offers ApiSession capabilities
    # implementing a compatible protocol.
    #
    # TODO(soon): How do we request a standard protocol that doesn't have a canonical URL, like
    #     WebDAV? Does any of ApiSession.PowerboxTag even make sense in this case?
    # TODO(soon): How do we request a single resource with a particular MIME type? Probably should
    #     be a separate interface, which http-bridge can implement...

    struct OAuthScope {
      name @0 :Text;
    }

    oauthScopes @1 :List(OAuthScope);
    # List of OAuth scopes required by the requesting app. OAuth APIs usually publish a list
    # of "scope" names representing permissions that can be requested. For example, see:
    #
    #     https://developer.github.com/v3/oauth/#scopes
    #
    # When this list is present (even if empty), it indicates that the requested API requires
    # OAuth-based authentication. The HTTP driver will guide the user through connecting their
    # Sandstorm account to the remote service and requesting the appropriate permissions.
    #
    # The Sandstorm project maintains an ad hoc mapping of hostnames to OAuth endpoints allowing
    # the HTTP driver to automatically determine what kind of OAuth request to make for a given
    # `canonicalUrl`. For example, if `canonicalUrl` is `https://api.github.com`, the HTTP driver
    # will initiate a Github OAuth handshake. For any URL under apidata.googleusercontent.com, the
    # driver will initiate a Google OAuth handshake. Etc. Unfortunately, it is not possible to
    # make OAuth requests to endpoints not on the list. However, we welcome pull requests to add
    # new endpoints, large or small.
    #
    # Sandstorm grains offering compatible APIs may wish to list the OAuth scopes they support.
    # Powerbox matching rules state that when a Powerbox query and potential matching descriptor
    # both contain a field of list-of-struct type, then they are treated as sets, and the match
    # must advertise a superset of the request. Therefore, if you list OAuth scopes when
    # publishing, then only requests for a subset of these will lead to your offer being listed in
    # the Powerbox. Often, offers will want to leave `oauthScopes` null, which will cause the scope
    # list to be ignored for matching purposes (always match).

    authentication @2 :Text;
    # If not null, indicates that this endpoint is expected to need old-fashion authentication.
    # The field contains a text string naming the type of authentication. Currently there is only
    # one type recognized: "basic", meaning HTTP Basic Auth. Specifying this instructs the HTTP
    # driver to prompt the user for a username and password.
    #
    # Note that even if this isn't specified, the HTTP driver will probe the target server to see
    # if it demands authentication and, if so, will prompt the user for a password anyway. Thus
    # this is only needed in cases where the target server supports both authenticated and
    # unauthenticated use and thus the probe will not notice the need for authentication.
    #
    # When publishing support of HTTP APIs to the Powerbox, you should usually leave this field
    # null, so that it is not considered for matching.
  }
}
using Go = import "/go.capnp";
$Go.package("apisession");
$Go.import("zenhack.net/go/sandstorm/capnp/apisession");
