Implement user persistence via Firebase (khanon/oai-reverse-proxy!8)

This commit is contained in:
nai-degen
2023-05-14 04:26:08 +00:00
parent 7126fb6c6c
commit f1ac64fa12
10 changed files with 1776 additions and 88 deletions
+204
View File
@@ -0,0 +1,204 @@
# Shat out by GPT-4, I did not check for correctness beyond a cursory glance
openapi: 3.0.0
info:
version: 1.0.0
title: User Management API
paths:
/admin/users:
get:
summary: List all users
operationId: getUsers
responses:
"200":
description: A list of users
content:
application/json:
schema:
type: object
properties:
users:
type: array
items:
$ref: "#/components/schemas/User"
count:
type: integer
format: int32
post:
summary: Create a new user
operationId: createUser
responses:
"200":
description: The created user's token
content:
application/json:
schema:
type: object
properties:
token:
type: string
put:
summary: Bulk upsert users
operationId: bulkUpsertUsers
requestBody:
content:
application/json:
schema:
type: object
properties:
users:
type: array
items:
$ref: "#/components/schemas/User"
responses:
"200":
description: The upserted users
content:
application/json:
schema:
type: object
properties:
upserted_users:
type: array
items:
$ref: "#/components/schemas/User"
count:
type: integer
format: int32
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: string
/admin/users/{token}:
get:
summary: Get a user by token
operationId: getUser
parameters:
- name: token
in: path
required: true
schema:
type: string
responses:
"200":
description: A user
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
description: Not found
content:
application/json:
schema:
type: object
properties:
error:
type: string
put:
summary: Update a user by token
operationId: upsertUser
parameters:
- name: token
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/User"
responses:
"200":
description: The updated user
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: string
delete:
summary: Disables the user with the given token
description: Optionally accepts a `disabledReason` query parameter. Returns the disabled user.
parameters:
- in: path
name: token
required: true
schema:
type: string
description: The token of the user to disable
- in: query
name: disabledReason
required: false
schema:
type: string
description: The reason for disabling the user
responses:
'200':
description: The disabled user
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: string
'404':
description: Not found
content:
application/json:
schema:
type: object
properties:
error:
type: string
components:
schemas:
User:
type: object
properties:
token:
type: string
ip:
type: array
items:
type: string
type:
type: string
enum: ["normal", "special"]
promptCount:
type: integer
format: int32
tokenCount:
type: integer
format: int32
createdAt:
type: integer
format: int64
lastUsedAt:
type: integer
format: int64
disabledAt:
type: integer
format: int64
disabledReason:
type: string
+65
View File
@@ -0,0 +1,65 @@
# User Management
The proxy supports several different user management strategies. You can choose the one that best fits your needs by setting the `GATEKEEPER` environment variable.
Several of these features require you to set secrets in your environment. If using Huggingface Spaces to deploy, do not set these in your `.env` file because that file is public and anyone can see it.
## Table of Contents
- [No user management](#no-user-management-gatekeepernone)
- [Single-password authentication](#single-password-authentication-gatekeeperproxy_key)
- [Per-user authentication](#per-user-authentication-gatekeeperuser_token)
- [Memory](#memory)
- [Firebase Realtime Database](#firebase-realtime-database)
- [Firebase setup instructions](#firebase-setup-instructions)
## No user management (`GATEKEEPER=none`)
This is the default mode. The proxy will not require any authentication to access the server and offers basic IP-based rate limiting and anti-abuse features.
## Single-password authentication (`GATEKEEPER=proxy_key`)
This mode allows you to set a password that must be passed in the `Authentication` header of every request to the server as a bearer token. This is useful if you want to restrict access to the server, but don't want to create a separate account for every user.
To set the password, create a `PROXY_KEY` secret in your environment.
## Per-user authentication (`GATEKEEPER=user_token`)
This mode allows you to provision separate Bearer tokens for each user. You can manage users via the /admin/users REST API, which itself requires an admin Bearer token.
To begin, set `ADMIN_KEY` to a secret value. This will be used to authenticate requests to the /admin/users REST API.
[You can find an OpenAPI specification for the /admin/users REST API here.](openapi-admin-users.yaml)
By default, the proxy will store user data in memory. Naturally, this means that user data will be lost when the proxy is restarted, though you can use the bulk user import/export feature to save and restore user data manually or via a script. However, the proxy also supports persisting user data to an external data store with some additional configuration.
Below are the supported data stores and their configuration options.
### Memory
This is the default data store (`GATEKEEPER_STORE=memory`) User data will be stored in memory and will be lost when the proxy is restarted. You are responsible for downloading and re-uploading user data via the REST API if you want to persist it.
### Firebase Realtime Database
To use Firebase Realtime Database to persist user data, set the following environment variables:
- `GATEKEEPER_STORE`: Set this to `firebase_rtdb`
- **Secret** `FIREBASE_RTDB_URL`: The URL of your Firebase Realtime Database, e.g. `https://my-project-default-rtdb.firebaseio.com`
- **Secret** `FIREBASE_KEY`: A base-64 encoded service account key for your Firebase project. Refer to the instructions below for how to create this key.
**Firebase setup instructions**
1. Go to the [Firebase console](https://console.firebase.google.com/) and click "Add project", then follow the prompts to create a new project.
2. From the **Project Overview** page, click **All products** in the left sidebar, then click **Realtime Database**.
3. Click **Create database** and choose **Start in test mode**. Click **Enable**.
- Test mode is fine for this use case as it still requires authentication to access the database. You may wish to set up more restrictive rules if you plan to use the database for other purposes.
- The reference URL for the database will be displayed on the page. You will need this later.
4. Click the gear icon next to **Project Overview** in the left sidebar, then click **Project settings**.
5. Click the **Service accounts** tab, then click **Generate new private key**.
6. The downloaded file contains your key. Encode it as base64 and set it as the `FIREBASE_KEY` secret in your environment.
7. Set `FIREBASE_RTDB_URL` to the reference URL of your Firebase Realtime Database, e.g. `https://my-project-default-rtdb.firebaseio.com`.
8. Set `GATEKEEPER_STORE` to `firebase_rtdb` in your environment if you haven't already.
The proxy will attempt to connect to your Firebase Realtime Database at startup and will throw an error if it cannot connect. If you see this error, check that your `FIREBASE_RTDB_URL` and `FIREBASE_KEY` secrets are set correctly.
---
Users are loaded from the database and changes are flushed periodically. You can use the PUT /admin/users API to bulk import users and force a flush to the database.