tinyagent
Version:
Connect your local shell to any device - access your dev environment from anywhere
218 lines ⢠9.27 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirebaseAuthClient = void 0;
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const open_1 = __importDefault(require("open"));
const http_1 = __importDefault(require("http"));
const url_1 = require("url");
class FirebaseAuthClient {
configPath;
token;
constructor() {
this.configPath = path_1.default.join(os_1.default.homedir(), '.tinyagent', 'auth.json');
this.loadToken();
}
loadToken() {
try {
if (fs_1.default.existsSync(this.configPath)) {
const data = fs_1.default.readFileSync(this.configPath, 'utf-8');
this.token = JSON.parse(data);
}
}
catch (error) {
// Ignore errors, token will be undefined
}
}
saveToken(token) {
try {
const dir = path_1.default.dirname(this.configPath);
if (!fs_1.default.existsSync(dir)) {
fs_1.default.mkdirSync(dir, { recursive: true });
}
fs_1.default.writeFileSync(this.configPath, JSON.stringify(token, null, 2));
this.token = token;
}
catch (error) {
console.error(chalk_1.default.yellow('Warning: Could not save auth token'));
}
}
isAuthenticated() {
if (!this.token)
return false;
if (this.token.expiresAt && this.token.expiresAt < Date.now()) {
return false;
}
return true;
}
getToken() {
return this.isAuthenticated() ? this.token?.idToken : undefined;
}
getUser() {
return this.isAuthenticated() ? this.token?.user : undefined;
}
async authenticate() {
console.log(chalk_1.default.cyan('\nš Authenticating with Firebase'));
try {
// Create local server to receive the callback
const server = http_1.default.createServer();
const port = 9005;
return new Promise((resolve) => {
let resolved = false;
server.on('request', async (req, res) => {
const url = new url_1.URL(req.url, `http://localhost:${port}`);
if (url.pathname === '/auth/callback') {
const idToken = url.searchParams.get('token');
const uid = url.searchParams.get('uid');
const email = url.searchParams.get('email');
const name = url.searchParams.get('name');
if (idToken && uid) {
try {
// Save token
this.saveToken({
idToken,
user: {
uid,
email: email || null,
displayName: name || null,
photoURL: null,
},
expiresAt: Date.now() + (60 * 60 * 1000), // 1 hour
});
// Send success response
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>Authentication Successful</title>
<style>
body {
font-family: -apple-system, system-ui, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #000;
color: #0f0;
}
.success { text-align: center; }
h1 { font-size: 48px; margin: 0; }
p { color: #888; margin-top: 10px; }
</style>
</head>
<body>
<div class="success">
<h1>ā</h1>
<p>Authentication successful! You can close this window.</p>
</div>
<script>setTimeout(() => window.close(), 2000)</script>
</body>
</html>
`);
console.log(chalk_1.default.green('\nā Authentication successful!'));
if (email) {
console.log(chalk_1.default.gray(`Logged in as: ${email}`));
}
if (!resolved) {
resolved = true;
server.close();
resolve(true);
}
}
catch (error) {
console.error(chalk_1.default.red('Failed to process authentication'));
res.writeHead(400);
res.end('Authentication failed');
if (!resolved) {
resolved = true;
server.close();
resolve(false);
}
}
}
else {
res.writeHead(400);
res.end('Missing authentication data');
if (!resolved) {
resolved = true;
server.close();
resolve(false);
}
}
}
else {
res.writeHead(404);
res.end('Not found');
}
});
server.listen(port, async () => {
// For now, we'll use a simple auth page hosted on Firebase
// In production, this would be your Firebase Hosting URL
const authUrl = `https://tinyagent-fab3c.firebaseapp.com/auth/cli?redirect=http://localhost:${port}/auth/callback`;
console.log(chalk_1.default.white('\nTo authenticate, visit:'));
console.log(chalk_1.default.green.bold(authUrl));
// Open browser
try {
await (0, open_1.default)(authUrl);
console.log(chalk_1.default.gray('\n(Browser should open automatically)'));
}
catch {
console.log(chalk_1.default.gray('\n(Please open the URL manually in your browser)'));
}
console.log(chalk_1.default.gray('\nWaiting for authentication...'));
});
// Timeout after 5 minutes
setTimeout(() => {
if (server.listening && !resolved) {
console.log(chalk_1.default.red('\nā Authentication timed out'));
resolved = true;
server.close();
resolve(false);
}
}, 5 * 60 * 1000);
});
}
catch (error) {
console.error(chalk_1.default.red('\nā Authentication failed:'), error);
return false;
}
}
logout() {
try {
if (fs_1.default.existsSync(this.configPath)) {
fs_1.default.unlinkSync(this.configPath);
}
this.token = undefined;
console.log(chalk_1.default.green('ā Logged out successfully'));
}
catch (error) {
console.error(chalk_1.default.red('ā Logout failed:'), error);
}
}
whoami() {
if (!this.isAuthenticated()) {
console.log(chalk_1.default.yellow('Not authenticated. Run "tinyagent login" to authenticate.'));
return;
}
const user = this.getUser();
if (user) {
console.log(chalk_1.default.cyan('Current user:'));
console.log(` UID: ${user.uid}`);
if (user.email) {
console.log(` Email: ${user.email}`);
}
if (user.displayName) {
console.log(` Name: ${user.displayName}`);
}
}
}
}
exports.FirebaseAuthClient = FirebaseAuthClient;
//# sourceMappingURL=firebase-auth-simple.js.map