Documentation
Everything you need to deploy, configure, and extend Point Edit Studio.
Getting Started
Installation
Point Edit Studio is a single folder. No database, no package manager, no build step.
# Clone or download the repository git clone https://github.com/pointedit/pointedit.io.git # Or just copy the _editor folder anywhere PHP runs cp -r _editor/ /var/www/html/ # That's it. Visit /_editor/ in your browser.
First login
The default master credentials are set in _editor/config.php:
// Before going live, generate a real bcrypt hash: // php -r "echo password_hash('your-password', PASSWORD_BCRYPT);" define('PE_MASTER_USERNAME', 'admin'); define('PE_MASTER_PASSWORD', '$2y$10$replace.me.with.a.real.bcrypt.hash'); define('PE_MASTER_TOTP_SECRET', ''); // leave blank for no 2FA
Log in at: http://your-server/_editor/ → enter username + password → if TOTP is set, enter code → done.
Adding your first site
After login, you'll see the dashboard. Click Add Site to configure a local or remote site. Sites are stored in _editor/sites.json.
Site Configuration
Sites are defined in _editor/sites.json. Two types: local (files on the same server) and remote (via the pe_api.php agent).
[
{
"id": "my-site",
"name": "My Website",
"type": "local",
"root": "/home/user/public_html",
"url": "https://example.com",
"created": "2026-01-01",
"status": "active"
},
{
"id": "client-site",
"name": "Client Site",
"type": "remote",
"url": "https://client-site.com",
"api_key": "sk-abc123...",
"created": "2026-01-01",
"status": "active"
}
]
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier, used internally and for user assignment |
name | string | Yes | Display name shown in the dashboard |
type | string | Yes | local or remote |
root | string | Local only | Absolute filesystem path to the site root |
url | string | Yes | Public URL of the site (used for preview iframe) |
api_key | string | Remote only | API key matching the one in pe_api.php on the remote server |
created | string | No | Creation date (informational) |
status | string | No | active or inactive |
User Management
Users are defined in _editor/users.json. Each user has a role (admin or client) and a list of site IDs they can access.
[
{
"username": "admin",
"password": "$2y$10$...",
"totp_secret": "",
"role": "admin",
"sites": ["*"],
"created": "2026-01-01",
"last_login": null
},
{
"username": "client1",
"password": "$2y$10$...",
"totp_secret": "",
"role": "client",
"sites": ["my-site"],
"created": "2026-01-01",
"last_login": null
}
]
| Field | Type | Description |
|---|---|---|
username | string | Login username |
password | string | Bcrypt hash — generate with password_hash() |
totp_secret | string | TOTP secret (set during enrollment, blank for no 2FA) |
role | string | admin — full access, manage sites/users. client — assigned sites only |
sites | array | Array of site IDs, or ["*"] for all sites |
Roles at a glance: Admins see all sites, can add/edit/remove sites, manage users, and reset TOTP. Clients see only assigned sites and use the same editor — but without admin controls.
API Reference
All API calls go to _editor/api.php?action=<name> with a JSON body (POST). Authenticated endpoints require a valid session cookie.
Auth actions
| Action | Auth | Body | Response |
|---|---|---|---|
login | No | {"username":"...","password":"..."} |
{"ok":true} or {"totp_required":true} |
login_totp | Half | {"code":"123456"} |
{"ok":true,"user":{...}} |
totp_enroll | Half | {} |
{"ok":true,"secret":"...","qr":"..."} (embedded QR SVG) |
totp_enroll_verify | Half | {"code":"123456","nonce":"..."} |
{"ok":true} |
logout | Yes | {} |
{"ok":true} |
check | — | {} |
{"ok":true,"user":{...}} if logged in, else error |
Site actions (admin only)
| Action | Body | Description |
|---|---|---|
list_sites | {} | List all sites (filtered by user role) |
switch_site | {"site_id":"..."} | Select active site for editing |
add_site | {"id":"...","name":"...","type":"local",...} | Create a new site |
edit_site | {"id":"...","name":"...",...} | Update an existing site |
remove_site | {"id":"..."} | Delete a site |
check_site | {"id":"..."} | Ping a site to verify connectivity |
File actions (requires active site)
| Action | Body | Description |
|---|---|---|
tree | {} | Get recursive directory tree of the site |
read | {"path":"/index.html"} | Read a file's content |
save | {"path":"/index.html","content":"..."} | Overwrite a file. Auto-creates .bak backup |
create | {"path":"/new.html","content":"..."} | Create a new file |
linked_css | {"path":"/index.html"} | Extract linked CSS files from an HTML file |
find_in_files | {"query":"search-term","regex":false} | Search across all files |
replace_in_files | {"find":"old","replace":"new","regex":false} | Find and replace across all files |
images | {} | List all image files in the site |
seo_audit | {} | Crawl HTML files for SEO metadata |
list_templates | {} | List available templates in _editor/templates/ |
read_template | {"name":"event-template"} | Read a template with placeholders |
Example: reading a file and saving a change
# Step 1 — Login curl -X POST https://your-server/_editor/api.php?action=login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"your-password"}' \ -c cookies.txt # Step 2 — Read a file curl -X POST https://your-server/_editor/api.php?action=read \ -H "Content-Type: application/json" \ -d '{"path":"/index.html"}' \ -b cookies.txt # Step 3 — Save changes (auto-backup created) curl -X POST https://your-server/_editor/api.php?action=save \ -H "Content-Type: application/json" \ -d '{"path":"/index.html","content":"<h1>Updated</h1>"}' \ -b cookies.txt
Extension System
Extensions are PHP files dropped into _editor/extensions/. They can register new file types and add custom API functionality.
Creating an extension
Create a .php file in _editor/extensions/ with a manifest docblock:
/** My Extension v1.0 */ if (!defined('PE_VERSION')) { http_response_code(403); exit; } // Your extension logic here // This file is autoloaded when the extension system runs
Registering file types
Extensions can register additional file extensions for editing via the API:
curl -X POST /_editor/api.php?action=register_file_types \
-H "Content-Type: application/json" \
-d '{"extension_name":"JS Support","file_types":["js","jsx","ts","tsx"]}'
| Action | Body | Description |
|---|---|---|
list_extensions | {} | List installed extension files |
install_extension | multipart form ext_file | Upload a .php extension file |
register_file_types | {"extension_name":"...","file_types":["js","ts"]} | Register new editable file types |
unregister_file_types | {"extension_name":"..."} | Remove a file type registration |
get_registered_types | {} | List all registered and core file types |
Security: Extension files are scanned for dangerous functions (eval, system, exec, etc.) during upload. Only admin users can install extensions.
Remote Agent
The remote agent (pe_api.php) is a single PHP file deployed to client servers. It lets you edit remote sites through the Point Edit Studio dashboard as if they were local.
Deploying the agent
# Set your API key in pe_api.php first define('PE_API_KEY', 'sk-your-secret-key-here'); # Deploy to the client server scp _editor/pe_api.php user@client-server:/home/user/public_html/ # Add as a remote site in your dashboard with the same API key
Remote agent API
All agent calls require the X-PE-API-Key header:
curl -X POST https://client-site.com/pe_api.php?action=tree \
-H "Content-Type: application/json" \
-H "X-PE-API-Key: sk-your-secret-key-here" \
-d '{}'
| Action | Description |
|---|---|
ping | Health check — returns {"ok":true,"version":"..."} |
tree | Recursive directory listing |
read | Read file content (max 2MB) |
save | Save file content (auto-backup to /.pe_backups/) |
linked_css | Extract linked stylesheets from HTML |
find_in_files | Search across all files |
replace_in_files | Find and replace across all files |
images | Scan for image files |
seo_audit | SEO analysis of HTML files |
Security
Authentication
- Two-factor: TOTP (RFC 6238) with embedded QR code — zero external dependencies.
- Brute force: 5 failed attempts triggers a 15-minute lockout on the username.
- Sessions: 2-hour timeout by default (configurable via
PE_SESSION_TIMEOUT). IP-bound. SameSite=Strict cookies. - Passwords: bcrypt-hashed. Plaintext is never stored.
File system security
- Path traversal: All file paths are resolved through
safePath()which confirms the result is insidePE_ROOT. - Extension restrictions: Only files with allowed extensions can be edited (default:
html,htm,css,php). - File size limit: 2MB max file size (
PE_MAX_FILE_SIZE). - Hidden files: Files starting with
.and the_editordirectory itself are excluded from file trees.
Server hardening
The included .htaccess provides:
- Deny access to
.json,.bak, and.pe_tmp.*files - Disable directory listing
- Disable dangerous PHP functions (
exec,shell_exec, etc.) - CSP headers: script from self only, fonts from Google Fonts, images from anywhere
- Block direct access to
config.php,sites.json, andusers.json
Templates
Templates are HTML files in _editor/templates/ that use {{placeholder}} syntax. They can be read via the API and used as starting points for new pages. The included event-template.html demonstrates a full event page with schema.org markup and The Ticketing Co widget integration.