Skip to content
KernelDeimos edited this page Nov 20, 2024 · 3 revisions

Group Endpoints

POST /group/create (auth required)

Description

Creates a group and returns a UID (UUID formatted). Groups do not have names, or any other descriptive attributes. Instead they are always identified with a UUID, and they have a metadata property.

The metadata property will always be given back to the client in the same way it was provided. The extra property, also an object, may be changed by the backend. The behavior of setting any property on extra is currently undefined as all properties are reserved for future use.

Parameters

  • metadata: - optional
    • accepts: object
    • description: arbitrary metadata to describe the group
  • extra: - optional
    • accepts: object
    • description: extra parameters (server may change these)

Request Example

await fetch(`${window.api_origin}/group/create`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
    metadata: { title: 'Some Title' }
  }),
  "method": "POST",
});

// { uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6' }

Response Example

{
    "uid": "9c644a1c-3e43-4df4-ab67-de5b68b235b6"
}

POST /group/add-users

Description

Adds one or more users to a group

Parameters

  • uid: - required
    • accepts: string UUID of an existing group
  • users: Array<string> usernames of users to add to the group

Request Example

await fetch(`${window.api_origin}/group/add-users`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
      users: ['first_user', 'second_user'],
  }),
  "method": "POST",
});

POST /group/remove-users

Description

Remove one or more users from a group

Parameters

  • uid: - required
    • accepts: string UUID of an existing group
  • users: Array<string> usernames of users to remove from the group

Request Example

await fetch(`${window.api_origin}/group/add-users`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
      users: ['first_user', 'second_user'],
  }),
  "method": "POST",
});

GET /group/list

Description

List groups associated with the current user

Parameters

none

Response Example

{
    "owned_groups": [
        {
            "uid": "c3bd4047-fc65-4da8-9363-e52195890de4",
            "metadata": {},
            "members": [
                "default_user"
            ]
        }
    ],
    "in_groups": [
        {
            "uid": "c3bd4047-fc65-4da8-9363-e52195890de4",
            "metadata": {},
            "members": [
                "default_user"
            ]
        }
    ]
}

Group Permission Endpoints

POST /grant-user-group

Grant permission from the current user to a group. This creates an association between the user and the group for this permission; the group will only have the permission effectively while the user who granted permission has the permission.

Parameters

  • group_uid: - required
    • accepts: string UUID of an existing group
  • permission: - required
    • accepts: string A permission string

Request Example

await fetch("http://puter.localhost:4100/auth/grant-user-group", {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      group_uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
      permission: 'fs:/someuser/somedir/somefile:read'
  }),
  "method": "POST",
});

POST /revoke-user-group

Revoke permission granted from the current user to a group.

Parameters

  • group_uid: - required
    • accepts: string UUID of an existing group
  • permission: - required
    • accepts: string A permission string

Request Example

await fetch("http://puter.localhost:4100/auth/grant-user-group", {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      group_uid: '9c644a1c-3e43-4df4-ab67-de5b68b235b6',
      permission: 'fs:/someuser/somedir/somefile:read'
  }),
  "method": "POST",
});
  • TODO figure out how to manage documentation that could reasonably show up in two files. For example: this is a group endpoint as well as a permission system endpoint. (architecturally it's a permission system endpoint, and the permissions feature depends on the groups feature; at least until a time when PermissionService is refactored so a service like GroupService can mutate the permission check sequences)

Notification Endpoints

Endpoints for managing notifications.

POST /notif/mark-ack (auth required)

Description

The /notif/mark-ack endpoint marks the specified notification as "acknowledged". This indicates that the user has chosen to either dismiss or act on this notification.

Parameters

Name Description Default Value
uid UUID associated with the notification required

Response

This endpoint responds with an empty object ({}).

POST /notif/mark-read (auth required)

Description

The /notif/mark-read endpoint marks that the specified notification has been shown to the user. It will not "pop up" as a new notification if they load the gui again.

Parameters

Name Description Default Value
uid UUID associated with the notification required

Response

This endpoint responds with an empty object ({}).

Request Example

await fetch("https://api.puter.local/notif/mark-read", {
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  body: JSON.stringify({
    uid: 'a14ea3d5-828b-42f9-9613-35f43b0a3cb8',
  }),
  method: "POST",
});

ENTITY STORAGE puter-notifications

The puter-notifications driver is an Entity Storage driver. It is read-only.

Request Examples

Select Unread Notifications

await fetch("http://api.puter.localhost:4100/drivers/call", {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
    interface: 'puter-notifications',
    method: 'select',
    args: { predicate: ['unread'] }
  }),
  "method": "POST",
});

Select First 200 Notifications

await fetch("http://api.puter.localhost:4100/drivers/call", {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
    interface: 'puter-notifications',
    method: 'select',
    args: {}
  }),
  "method": "POST",
});

Select Next 200 Notifications

await fetch("http://api.puter.localhost:4100/drivers/call", {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
    interface: 'puter-notifications',
    method: 'select',
    args: { offset: 200 }
  }),
  "method": "POST",
});

Share Endpoints

Share endpoints allow sharing files with other users.

POST /share (auth required)

Description

The /share endpoint shares 1 or more filesystem items with one or more recipients. The recipients will receive some notification about the shared item, making this different from calling /grant-user-user with a permission.

When users are specified by email they will receive a share link.

Each item specified in the shares property is a tag-typed object of type fs-share or app-share.

File Shares (fs-share)

File shares grant permission to a file or directory. By default this is read permission. If access is specified as "write", then write permission will be granted.

App Shares (app-share)

App shares grant permission to read a protected app.

subdomain permission

If there is a subdomain associated with the app, and the owner of the subdomain is the same as the owner of the app, then permission to access the subdomain will be granted. Note that the subdomain is only associated if the subdomain entry has associated_app_id set according to the app's id, and will not be considered "associated" if only the index_url happens to match the subdomain url.

appdata permission

If the app has shared_appdata set to true in its metadata object, the recipient of the share will also get write permission to the app owner's corresponding appdata directory. The appdata directory must exist for this to work as expected (otherwise the permission rewrite rule fails since the uuid can't be determined).

Example

{
    "recipients": [
        "user_that_gets_shared_to",
        "[email protected]"
    ],
    "shares": [
        {
            "$": "app-share",
            "name": "some-app-name"
        },
        {
            "$": "app-share",
            "uid": "app-SOME-APP-UID"
        },
        {
            "$": "fs-share",
            "path": "/some/file/or/directory"
        },
        {
            "$": "fs-share",
            "path": "SOME-FILE-UUID"
        }
    ]
}

Parameters

  • recipients - required
    • accepts: string | Array<string>
    • description: recipients for the filesystem entries being shared.
    • notes:
      • validation on string: email or username
      • requirement of at least one value
  • shares: - required
    • accepts: object | Array<object>
    • notes:
      • requirement that file/directory or app exists
      • requirement of at least one entry
  • dry_run: - optional
    • accepts: bool
    • description: when true, only validation will occur

Response

  • $: api:share
  • $version: v0.0.0
  • status: one of: "success", "mixed", "aborted"
  • recipients: array of: api:status-report or heyputer:api/APIError
  • paths: array of: api:status-report or heyputer:api/APIError
  • dry_run: true if present

Request Example

await fetch("http://puter.localhost:4100/share", {
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  body: JSON.stringify({
    recipients: [
        "user_that_gets_shared_to",
        "[email protected]"
    ],
    shares: [
        {
            $: "app-share",
            name: "some-app-name"
        },
        {
            $: "app-share",
            uid: "app-SOME-APP-UID"
        },
        {
            $: "fs-share",
            path: "/some/file/or/directory"
        },
        {
            $: "fs-share",
            path: "SOME-FILE-UUID"
        }
    ]
  }),
  method: "POST",
});

Success Response

{
    "$": "api:share",
    "$version": "v0.0.0",
    "status": "success",
    "recipients": [
        {
            "$": "api:status-report",
            "status": "success"
        }
    ],
    "paths": [
        {
            "$": "api:status-report",
            "status": "success"
        }
    ],
    "dry_run": true
}

Error response (missing file)

{
    "$": "api:share",
    "$version": "v0.0.0",
    "status": "mixed",
    "recipients": [
        {
            "$": "api:status-report",
            "status": "success"
        }
    ],
    "paths": [
        {
            "$": "heyputer:api/APIError",
            "code": "subject_does_not_exist",
            "message": "File or directory not found.",
            "status": 404
        }
    ],
    "dry_run": true
}

Error response (missing user)

{
    "$": "api:share",
    "$version": "v0.0.0",
    "status": "mixed",
    "recipients": [
        {
            "$": "heyputer:api/APIError",
            "code": "user_does_not_exist",
            "message": "The user `non_existing_user` does not exist.",
            "username": "non_existing_user",
            "status": 422
        }
    ],
    "paths": [
        {
            "$": "api:status-report",
            "status": "success"
        }
    ],
    "dry_run": true
}

POST /sharelink/check (no auth)

Description

The /sharelink/check endpoint verifies that a token provided by a share link is valid.

Example

await fetch(`${config.api_origin}/sharelink/check`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      token: '...',
  }),
  "method": "POST",
});

Parameters

  • token: - required
    • accepts: string The token from the querystring parameter

Response

A type-tagged object, either of type api:share or api:error

Success Response

{
    "$": "api:share",
    "uid": "836671d4-ac5d-4bd3-bc0a-ec357e0d8f02",
    "email": "[email protected]"
}

Error Response

{
    "$": "api:error",
    "message":"Field `token` is required.",
    "key":"token",
    "code":"field_missing"
}

POST /sharelink/apply (no auth)

Description

The /sharelink/apply endpoint applies a share to the current user if and only if that user's email is confirmed and matches the email associated with the share.

Example

await fetch(`${config.api_origin}/sharelink/apply`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      uid: '836671d4-ac5d-4bd3-bc0a-ec357e0d8f02',
  }),
  "method": "POST",
});

Parameters

  • uid: - required
    • accepts: string The uid of an existing share, received using /sharelink/check

Response

A type-tagged object, either of type api:status-report or api:error

Success Response

{"$":"api:status-report","status":"success"}

Error Response

{
    "message": "This share can not be applied to this user.",
    "code": "can_not_apply_to_this_user"
}

POST /sharelink/request (no auth)

Description

The /sharelink/request endpoint requests the permissions associated with a share link to the issuer of the share (user that sent the share). This can be used when a user is logged in, but that user's email does not match the email associated with the share.

Example

await fetch(`${config.api_origin}/sharelink/request`, {
  "headers": {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  "body": JSON.stringify({
      uid: '836671d4-ac5d-4bd3-bc0a-ec357e0d8f02',
  }),
  "method": "POST",
});

Parameters

  • uid: - required
    • accepts: string The uid of an existing share, received using /sharelink/check

Response

A type-tagged object, either of type api:status-report or api:error

Success Response

{"$":"api:status-report","status":"success"}

Error Response

{
    "message": "This share is already valid for this user; POST to /apply for access",
    "code": "no_need_to_request"
}

ACL Endpoints

POST /acl/stat-user-user (auth required)

Reports permissions that the current user has granted to the specified user on the specified file, or any affecting parents of the file.

The response contains a property called permissions which holds an object. This object has file path keys, and each value is a list of permissions granted on the respective file path. Typically there will only be one permission per path if all access to shared resources was granted via ACLService. It is possible to grant redundant permissions (i.e. both read and write on the same file) via PermissionService directly. In this case, ACL treats the most permissive permission as the effective permission. Any further action through ACLService (ex: via /acl/set-user-user) will result in redundant permissions being removed.

Parameters

  • user: - required
    • accepts: string username of the holder of permissions issued by the current user
  • resource: - required
    • accepts: string path or UUID of a file

Request Example

await (await fetch("http://puter.localhost:4100/acl/stat-user-user", {
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${puter.authToken}`,
  },
  body: JSON.stringify({
      user: 'ed3',
      resource: '/admin/Desktop/shared_dir/sub_dir/share_test.txt'
  }),
  method: "POST",
})).json();

Response Example

{
    "permissions": {
        "/admin/Desktop/shared_dir/sub_dir/share_test.txt": [
            "fs:940685b5-5e96-4922-80b0-5504c417e1d6:write"
        ],
        "/admin/Desktop/shared_dir": [
            "fs:fc35cce1-0b1a-44ed-8b60-21455decd99c:read"
        ]
    }
}

POST /acl/set-user-user (auth required)

Revokes and/or grants permissions on a file to the specified user according to the specified desired access mode.

Parameters

  • user: - required
    • accepts: string This is the user accessing the file. Permissions between the current user (the issuer), and this specified user (the holder), will be modified to achieve the desired access mode.
  • resource: - required
    • accepts: string path or UUID of a file
  • mode: - required
    • accepts: string The desired access mode; read, write, see, or list.
  • options: - optional
    • accepts: object This is an options object with the following parameters:
      • only_if_higher - If this is set to true, access will only be modified if the user doesn't have equivalent or higher access to the resource already. If the user has equivalent or higher access due to a parent directory, the permission will still be set on the resource.

Example


# Type-Tagged Objects

```js
{
    "$": "some-type",
    "$version": "0.0.0",
    
    "some_property": "some value",
}

What's a Type-Tagged Object?

Type-Tagged objects are a convention understood by Puter's backend to communicate meta information along with a JSON object. The key feature of Type-Tagged Objects is the type key: "$".

Why Type-Tagged Objects?

The primary reason: to have a consistent convention we can use anywhere.

  • Since other services rarely use $ in their property names, we can safely use this without introducing reserved words and re-mapping property names.
  • Some places we use this convention might not need it, but staying consistent means API end-users can do more with less code.

Specification

  • The "$" key indicates a type (or class) of object
  • Any other key beginning with $ is a meta-key
  • Other keys are not allowed to contain $
  • "$version" must follow semver
  • Keys with multiple "$" symbols are reserved for future use

Alternative Representations

Puter's API will always send results in the format described above, which is called the "Standard Representation"

Any endpoint which accepts a Type-Tagged Object will also accept these alternative representations:

Structured Representation

Depending on the architecture of your client, this format may be more convenient to work with:

{
    "$": "$meta-body",
    "type": "some-type",
    "meta": { "version": "0.0.0" },
    "body": { "some_property": "some value" }
}

Array Representation

In the array representation, meta values go at the end.

["some-type",
    { "some_property": "some value" },
    { "version": "0.0.0" }
]

If the second element of the list is not an object, it will implicitly be placed in a property called value. The following are equivalent:

["some-type", "hello"]
["some-type", { "value": "hello" }]

{"$": "app-share"} - App Share

Structure

  • name: name of the app
  • uid: name of the app

Notes

  • One of name or uid must be specified

Examples

Share app by name

{
    "$": "app-share",
    "name": "some-app-name"
}

Share app by uid

{
    "$": "app-share",
    "uid": "app-0a7337f7-0f8a-49ca-b71a-38d39304fe04"
}

{"$": "file-share"} - File Share

Structure

  • path: file or directory's path or uuid
  • access: one of: "read", "write" (default: "read")

Examples

Share with read access

{
    "$": "file-share",
    "path": "/some/path"
}

Share with write access

{
    "$": "file-share",
    "path": "/some/path",
    "access": "write"
}

Using a UUID

{
    "$": "file-share",
    "path": "b912c381-0c0b-466c-95a6-f9a4fc680a7d"
}

Share Links

A share link is a link to Puter's origin which contains a token in the query string (the key is share_token; ex: http://puter.localhost:4100?share_token=...).

This token can be used to apply permissions to the user of the current session if and only if this user's email is confirmed and matches the share link's associated email.

Init

Utilities

Extension API

Clone this wiki locally