appwrite-utils-cli
Version:
Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.
165 lines (164 loc) • 5.6 kB
JavaScript
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
import { MessageFormatter } from "../shared/messageFormatter.js";
/**
* Normalizes an endpoint URL by removing trailing slashes and converting to lowercase
*/
function normalizeEndpoint(url) {
return url.replace(/\/+$/, "").toLowerCase();
}
/**
* Load session preferences from ~/.appwrite/prefs.json
*/
export function loadSessionPrefs() {
try {
const prefsPath = join(homedir(), ".appwrite", "prefs.json");
if (!existsSync(prefsPath)) {
return null;
}
const prefsContent = readFileSync(prefsPath, "utf-8");
const prefs = JSON.parse(prefsContent);
return prefs;
}
catch (error) {
MessageFormatter.warning("Failed to load Appwrite session preferences", { prefix: "Session" });
return null;
}
}
/**
* Get session authentication info for a specific project
*/
export function getSessionAuth(projectId) {
const prefs = loadSessionPrefs();
if (!prefs || !prefs[projectId]) {
return null;
}
const sessionData = prefs[projectId];
// Validate session data structure
if (!sessionData.endpoint || !sessionData.cookie) {
MessageFormatter.warning(`Invalid session data for project ${projectId}`, { prefix: "Session" });
return null;
}
return {
projectId,
endpoint: sessionData.endpoint,
sessionCookie: sessionData.cookie,
email: sessionData.email,
};
}
/**
* Check if a session cookie appears to be valid (enhanced validation)
*/
export function isValidSessionCookie(cookie) {
if (!cookie || typeof cookie !== "string") {
return false;
}
// Trim whitespace
cookie = cookie.trim();
// Basic length check
if (cookie.length < 10) {
return false;
}
// Basic validation - Appwrite session cookies are typically JWT-like
// They should contain dots and be reasonably long
if (!cookie.includes(".")) {
return false;
}
// Check for obviously expired or malformed tokens
// JWT tokens typically have 3 parts separated by dots
const parts = cookie.split('.');
if (parts.length < 2) {
return false;
}
// Additional validation - ensure it's not obviously corrupted
// Should contain alphanumeric characters and common JWT characters
const validChars = /^[A-Za-z0-9._-]+$/;
if (!validChars.test(cookie)) {
return false;
}
return true;
}
/**
* Get all available sessions from prefs
*/
export function getAvailableSessions() {
const prefs = loadSessionPrefs();
if (!prefs) {
return [];
}
const sessions = [];
for (const [projectId, sessionData] of Object.entries(prefs)) {
if (sessionData.endpoint && sessionData.cookie && isValidSessionCookie(sessionData.cookie)) {
sessions.push({
projectId,
endpoint: sessionData.endpoint,
sessionCookie: sessionData.cookie,
email: sessionData.email,
});
}
}
return sessions;
}
/**
* Find session by endpoint and project combination
*/
export function findSessionByEndpointAndProject(endpoint, projectId) {
const sessionAuth = getSessionAuth(projectId);
if (!sessionAuth) {
MessageFormatter.debug(`No session found for project ${projectId}`, { prefix: "Session" });
return null;
}
// Normalize endpoints for comparison (remove trailing slashes, etc.)
if (normalizeEndpoint(sessionAuth.endpoint) !== normalizeEndpoint(endpoint)) {
MessageFormatter.warning(`Session endpoint mismatch for project ${projectId}:\n` +
` Session endpoint: ${sessionAuth.endpoint}\n` +
` Config endpoint: ${endpoint}\n` +
` Tip: Run 'appwrite login' to update session for this endpoint`, { prefix: "Session" });
return null;
}
return sessionAuth;
}
/**
* Check if session authentication is available for a project configuration
*/
export function hasSessionAuth(endpoint, projectId) {
const sessionAuth = findSessionByEndpointAndProject(endpoint, projectId);
return sessionAuth !== null && isValidSessionCookie(sessionAuth.sessionCookie);
}
/**
* Get detailed authentication status for debugging and error reporting
*/
export function getAuthenticationStatus(endpoint, projectId) {
const sessionAuth = getSessionAuth(projectId);
if (!sessionAuth) {
return {
hasValidSession: false,
sessionExists: false,
endpointMatches: false,
cookieValid: false,
message: `No session found for project ${projectId}. Run 'appwrite login' to authenticate.`
};
}
const endpointMatches = normalizeEndpoint(sessionAuth.endpoint) === normalizeEndpoint(endpoint);
const cookieValid = isValidSessionCookie(sessionAuth.sessionCookie);
const hasValidSession = endpointMatches && cookieValid;
let message = "";
if (!endpointMatches) {
message = `Session endpoint mismatch. Expected: ${endpoint}, Found: ${sessionAuth.endpoint}`;
}
else if (!cookieValid) {
message = `Session cookie is invalid or expired for project ${projectId}`;
}
else {
message = `Valid session found for ${sessionAuth.email || 'unknown user'}`;
}
return {
hasValidSession,
sessionExists: true,
endpointMatches,
cookieValid,
sessionInfo: sessionAuth,
message
};
}