From bab5f0de7dceb406a560389f88f87aa884f4fb07 Mon Sep 17 00:00:00 2001 From: rooyca Date: Tue, 31 Mar 2026 03:42:07 -0500 Subject: [PATCH] update(doc): added spanish & chinese --- CONTRIBUTING.md | 371 +++++++++++++++++++ README.es.md | 63 +++- README.md | 41 +++ README.zh.md | 103 ++++-- docs/docs/en/codeblocks.md | 410 +++++++++++++++++---- docs/docs/en/index.md | 70 +++- docs/docs/es/codeblocks.md | 502 +++++++++++++++++++++++--- docs/docs/es/index.md | 80 ++++- docs/docs/es/usecase/index.md | 51 ++- docs/docs/zh/codeblocks.md | 580 +++++++++++++++++++++++++----- docs/docs/zh/index.md | 80 ++++- docs/docs/zh/usecase/index.md | 50 ++- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- src/functions/frontmatterUtils.ts | 19 +- src/functions/general.ts | 10 +- src/functions/regx.ts | 18 +- src/functions/security.ts | 196 ++++++++++ src/main.ts | 444 ++++++++++++++++++----- src/settings/settingsData.ts | 26 +- 21 files changed, 2729 insertions(+), 391 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 src/functions/security.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e4dcc0b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,371 @@ +# Contributing to API Request Plugin + +Thank you for your interest in contributing to the API Request plugin! This document provides guidelines and information for contributors. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Getting Started](#getting-started) +- [Development Setup](#development-setup) +- [Making Changes](#making-changes) +- [Code Style](#code-style) +- [Testing](#testing) +- [Submitting Changes](#submitting-changes) +- [Reporting Bugs](#reporting-bugs) +- [Requesting Features](#requesting-features) + +## Code of Conduct + +Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md). + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/obsidian-api-request.git` +3. Create a branch: `git checkout -b feature/your-feature-name` + +## Development Setup + +### Prerequisites + +- Node.js (v16 or higher) +- npm (v7 or higher) +- Obsidian (for testing) + +### Installation + +```bash +# Install dependencies +npm install + +# Build the plugin +npm run build + +# Development mode (auto-rebuild on changes) +npm run dev +``` + +### Project Structure + +``` +obsidian-api-request/ +├── src/ +│ ├── main.ts # Main plugin file +│ ├── functions/ +│ │ ├── general.ts # General utility functions +│ │ ├── regx.ts # Regular expressions +│ │ ├── security.ts # Security utilities +│ │ └── frontmatterUtils.ts # Frontmatter parsing +│ └── settings/ +│ ├── settingsData.ts # Settings interface +│ └── settingsTab.ts # Settings UI +├── docs/ # Documentation +├── main.js # Compiled output +├── manifest.json # Plugin manifest +└── package.json # Dependencies +``` + +## Making Changes + +### Branch Naming + +- `feature/` - New features +- `fix/` - Bug fixes +- `docs/` - Documentation updates +- `refactor/` - Code refactoring +- `security/` - Security improvements + +### Commit Messages + +Follow conventional commits format: + +``` +type(scope): brief description + +Longer description if needed + +- Additional details +- More details +``` + +Types: +- `feat`: New feature +- `fix`: Bug fix +- `docs`: Documentation changes +- `refactor`: Code refactoring +- `perf`: Performance improvements +- `test`: Adding or updating tests +- `security`: Security improvements + +Examples: +``` +feat(request): add support for PATCH method + +fix(cache): prevent race condition in localStorage + +docs(readme): add security best practices section + +security(validation): sanitize UUID input to prevent injection +``` + +## Code Style + +### TypeScript + +- Use TypeScript for all new code +- Add proper type annotations +- Avoid `any` type when possible +- Use interfaces for complex types + +### Documentation + +- Add JSDoc comments to all public functions +- Include `@param`, `@returns`, `@throws` tags +- Add `@example` for complex functions +- Document security considerations with `@security` tag + +Example: +```typescript +/** + * Validates a URL to ensure it's safe to request + * + * @param url - The URL to validate + * @returns true if valid, false otherwise + * @security Only allows http:// and https:// protocols + * @example + * isValidUrl("https://api.example.com") // returns true + * isValidUrl("file:///etc/passwd") // returns false + */ +export function isValidUrl(url: string): boolean { + // implementation +} +``` + +### Code Organization + +- Keep functions focused and single-purpose +- Extract magic numbers to constants +- Use descriptive variable names +- Limit function length to ~50 lines + +### Error Handling + +- Always wrap risky operations in try-catch +- Log errors to console with context +- Show user-friendly error messages via Notice +- Never expose sensitive data in errors + +Example: +```typescript +try { + const data = localStorage.getItem(key); + if (data) { + return safeJsonParse(data); + } +} catch (e: any) { + console.error("Error reading from localStorage:", e); + new Notice("Error: Failed to retrieve cached data"); + return null; +} +``` + +## Testing + +### Manual Testing + +1. Build the plugin: `npm run build` +2. Copy `main.js`, `manifest.json`, and `styles.css` to your Obsidian vault's plugins folder +3. Reload Obsidian +4. Test your changes thoroughly + +### Test Cases to Verify + +- URL validation with various protocols +- UUID sanitization with special characters +- JSONPath injection attempts +- File path traversal attempts +- XSS prevention in format strings +- Error handling for network failures +- localStorage cache operations +- Variable substitution (global, frontmatter, localStorage) + +### Security Testing + +Before submitting security-related changes: + +1. Test with malicious inputs +2. Verify input sanitization +3. Check for XSS vulnerabilities +4. Test error handling edge cases +5. Review console logs for sensitive data leaks + +## Submitting Changes + +### Pull Request Process + +1. Update documentation if needed +2. Add yourself to contributors if first contribution +3. Ensure the build passes: `npm run build` +4. Update CHANGELOG.md if significant change +5. Create a pull request with: + - Clear title describing the change + - Description of what and why + - Related issue numbers + - Screenshots for UI changes + - Testing steps + +### Pull Request Template + +```markdown +## Description +Brief description of changes + +## Type of Change +- [ ] Bug fix +- [ ] New feature +- [ ] Breaking change +- [ ] Documentation update +- [ ] Security improvement + +## Testing +Steps to test the changes + +## Checklist +- [ ] Code follows project style guidelines +- [ ] Added/updated documentation +- [ ] Tested manually +- [ ] No console errors +- [ ] Updated CHANGELOG.md +``` + +### Review Process + +- Maintainers will review your PR +- Address feedback and requested changes +- Once approved, your PR will be merged + +## Reporting Bugs + +### Before Reporting + +1. Check existing issues +2. Verify you're using the latest version +3. Reproduce the bug with minimal configuration + +### Bug Report Template + +```markdown +**Description** +Clear description of the bug + +**To Reproduce** +Steps to reproduce: +1. Go to '...' +2. Click on '...' +3. See error + +**Expected Behavior** +What should happen + +**Actual Behavior** +What actually happens + +**Screenshots** +If applicable + +**Environment** +- Plugin version: +- Obsidian version: +- OS: + +**Additional Context** +Any other relevant information +``` + +## Requesting Features + +### Feature Request Template + +```markdown +**Problem Statement** +What problem does this solve? + +**Proposed Solution** +How should it work? + +**Alternatives Considered** +Other approaches considered + +**Additional Context** +Examples, mockups, related issues +``` + +## Security Issues + +**Do not report security vulnerabilities in public issues!** + +See [SECURITY.md](SECURITY.md) for how to report security issues. + +## Code Review Guidelines + +When reviewing code: + +1. **Functionality**: Does it work as intended? +2. **Security**: Are inputs validated? Any XSS risks? +3. **Performance**: Any unnecessary operations? +4. **Maintainability**: Is the code clear and documented? +5. **Consistency**: Does it follow project conventions? + +## Development Tips + +### Hot Reload + +For faster development: +1. Run `npm run dev` to watch for changes +2. Use Obsidian's developer tools (Ctrl+Shift+I) +3. Reload plugin: Ctrl+R in dev tools + +### Debugging + +```typescript +// Add debug logging +console.log("Debug:", variable); + +// Use Obsidian's Notice for user feedback +new Notice("Debug: Operation completed"); + +// Use debugger breakpoints +debugger; +``` + +### Common Issues + +**Build fails**: +- Check TypeScript errors: `npm run build` +- Verify all imports are correct +- Check for missing type definitions + +**Plugin not loading**: +- Verify manifest.json is correct +- Check Obsidian console for errors +- Ensure minAppVersion matches your Obsidian + +**Changes not appearing**: +- Rebuild: `npm run build` +- Reload Obsidian: Ctrl+R +- Check file is copied to correct location + +## Questions? + +- Open a discussion on GitHub +- Ask in issues (for bug-related questions) +- Check existing documentation + +## Recognition + +Contributors will be: +- Listed in the project README +- Mentioned in release notes +- Credited in the plugin description + +Thank you for contributing! 🎉 diff --git a/README.es.md b/README.es.md index 292d631..fedb090 100644 --- a/README.es.md +++ b/README.es.md @@ -8,9 +8,18 @@ [![English](https://img.shields.io/badge/English-8A2BE2)](README.md) [![中文](https://img.shields.io/badge/中文-8A2BE2)](README.zh.md) -Este plugin para [Obsidian](https://obsidian.md/) permite a los usuarios realizar solicitudes HTTP desde sus notas y mostrar la respuesta en un bloque de código, una ventana modal o pegarla directamente en su documento actual. -![req_img](showcase_1.gif) +Este plugin para [Obsidian](https://obsidian.md/) permite a los usuarios realizar solicitudes API directamente desde sus notas y mostrar las respuestas en bloques de código. + +## 🔒 Seguridad + +Este plugin implementa medidas de seguridad completas que incluyen: + +- Validación de entradas para URLs, rutas y datos de usuario +- Prevención de XSS mediante sanitización de HTML +- Protección contra ataques de directory traversal +- Evaluación segura de expresiones JSONPath +- Manejo seguro de localStorage ## 🚀 Instalación @@ -30,13 +39,47 @@ Este plugin se puede instalar desde Obsidian. ![showcase](showcase_2.gif) -## ✅ To-do +## ✅ Por hacer -- [x] Añadir más tipos de solicitudes (POST, PUT, DELETE) -- [x] Añadir soporte para autenticación -- [x] Guardar la respuesta en un archivo -- [x] Eliminar uno a uno del localStorage -- [ ] Traducir la documentación +> Consulta todos los cambios en [TODOS-v2.md](TODOS-v2.md) + +- [ ] Traducir (y actualizar) documentación +- [x] Reutilización de datos (sintaxis `{{ls.UUID>JSONPath}}`, donde `ls` significa `localStorage`) +- [x] Soporte para comentarios usando sintaxis `#` o `//` +- [x] Consulta en línea desde la respuesta (usando **Dataview**) +- [ ] Añadir pruebas (!!!) +- [ ] Re-implementar flag `repeat` (repetir solicitudes X veces o cada X segundos) +- [x] Mejoras de seguridad (validación de entradas, prevención de XSS, protección contra directory traversal) +- [x] Mejoras de seguridad de tipos TypeScript +- [x] Manejo completo de errores + +## 🤝 Contribuir + +¡Las contribuciones son bienvenidas! Por favor, lee nuestras [Guías de Contribución](CONTRIBUTING.md) antes de enviar un pull request. + +### Desarrollo + +```bash +# Instalar dependencias +npm install + +# Compilar +npm run build + +# Modo desarrollo (auto-recompilación) +npm run dev +``` + +Para más detalles, consulta [CONTRIBUTING.md](CONTRIBUTING.md). + +## 🔒 Mejores Prácticas de Seguridad + +Al usar este plugin: + +1. **Usa HTTPS**: Siempre usa URLs HTTPS para solicitudes API +2. **Protege las Claves API**: Almacena las claves API en variables globales, nunca en las notas +3. **Revisa Datos en Caché**: Limpia regularmente respuestas antiguas en caché +4. **Valida Fuentes**: Solo conéctate a endpoints API de confianza ## ❤️ Patrocinadores @@ -44,6 +87,6 @@ Este plugin se puede instalar desde Obsidian. ## ✍️ Comentarios y Contribuciones -Si encuentras algún problema o tienes comentarios sobre el plugin, no dudes en abrir un problema en el [repositorio de GitHub](https://github.com/Rooyca/obsidian-api-request). +Si encuentras algún problema o tienes comentarios sobre el plugin, no dudes en abrir un issue en el [repositorio de GitHub](https://github.com/Rooyca/obsidian-api-request). -¡Las contribuciones también son bienvenidas! \ No newline at end of file +¡Las contribuciones también son bienvenidas! diff --git a/README.md b/README.md index 5b563ce..470ce72 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ This [Obsidian](https://obsidian.md/) plugin enables users to make API requests directly within their notes and display the response in a code-block. +## 🔒 Security + +This plugin implements comprehensive security measures including: +- Input validation for URLs, paths, and user data +- XSS prevention through HTML sanitization +- Protection against directory traversal attacks +- Safe JSONPath expression evaluation +- Secure localStorage handling + ## 🚀 Installation The plugin can be installed from within Obsidian. @@ -37,6 +46,38 @@ The plugin can be installed from within Obsidian. - [x] Inline query from response (using **Dataview**) - [ ] Add tests (!!!) - [ ] Re-implement `repeat` flag (repeat requests X times or every X seconds) +- [x] Security improvements (input validation, XSS prevention, path traversal protection) +- [x] TypeScript type safety improvements +- [x] Comprehensive error handling + +## 🤝 Contributing + +Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTING.md) before submitting a pull request. + +### Development + +```bash +# Install dependencies +npm install + +# Build +npm run build + +# Development mode (auto-rebuild) +npm run dev +``` + +For more details, see [CONTRIBUTING.md](CONTRIBUTING.md). + +## 🔒 Security Best Practices + +When using this plugin: + +1. **Use HTTPS**: Always use HTTPS URLs for API requests +2. **Protect API Keys**: Store API keys in global variables, not in notes +3. **Review Cached Data**: Regularly clear old cached responses +4. **Validate Sources**: Only connect to trusted API endpoints + ## ❤️ Sponsors diff --git a/README.zh.md b/README.zh.md index 8c498ad..510a5bf 100644 --- a/README.zh.md +++ b/README.zh.md @@ -9,39 +9,82 @@ [![English](https://img.shields.io/badge/English-8A2BE2)](README.md) -这个[Obsidian](https://obsidian.md/)插件能让用户直接在笔记中进行 HTTP 请求,并在代码块、模式窗口中显示响应,或直接将其粘贴到活动文档中。 +这个[Obsidian](https://obsidian.md/)插件能让用户直接在笔记中进行 API 请求,并在代码块中显示响应。 + +## 🔒 安全性 + +本插件实现了全面的安全措施,包括: +- URL、路径和用户数据的输入验证 +- 通过 HTML 清理防止 XSS 攻击 +- 防止目录遍历攻击 +- 安全的 JSONPath 表达式评估 +- 安全的 localStorage 处理 + +## 🚀 安装 + +该插件可以从 Obsidian 内部安装。 + +### Obsidian 社区插件浏览器 + +- 转到 `设置` -> `社区插件` +- 确保 `受限模式` 已 **关闭** +- 点击 `浏览` +- 搜索 `APIRequest` +- 点击 `安装`,然后点击 `启用` + +## 🛠️ 使用 + +### [阅读文档](https://rooyca.github.io/obsidian-api-request/) + +## ✅ 待办事项 + +> 查看 [TODOS-v2.md](TODOS-v2.md) 中的所有更改 + +- [ ] 翻译(和更新)文档 +- [x] 数据重用(`{{ls.UUID>JSONPath}}` 语法,其中 `ls` 代表 `localStorage`) +- [x] 支持使用 `#` 或 `//` 语法的注释 +- [x] 从响应中进行内联查询(使用 **Dataview**) +- [ ] 添加测试(!!!) +- [ ] 重新实现 `repeat` 标志(重复请求 X 次或每 X 秒) +- [x] 安全改进(输入验证、XSS 防护、目录遍历保护) +- [x] TypeScript 类型安全改进 +- [x] 全面的错误处理 + +## 🤝 贡献 + +欢迎贡献!在提交 pull request 之前,请阅读我们的[贡献指南](CONTRIBUTING.md)。 + +### 开发 + +```bash +# 安装依赖 +npm install + +# 构建 +npm run build + +# 开发模式(自动重建) +npm run dev +``` + +有关更多详细信息,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 + +## 🔒 安全最佳实践 + +使用此插件时: + +1. **使用 HTTPS**:进行 API 请求时始终使用 HTTPS URL +2. **保护 API 密钥**:将 API 密钥存储在全局变量中,而不是在笔记中 +3. **审查缓存数据**:定期清除旧的缓存响应 +4. **验证来源**:仅连接到受信任的 API 端点 -## 🚀 Installation - -The plugin can be installed from within Obsidian. - -### Obsidian Community Plugin Browser - -- Go to `Settings` -> `Community plugins` -- Make sure `Restricted mode` is **off** -- Click `Browse` -- Search for `APIRequest` -- Click `Install` and then `Enable` - -## 🛠️ Usage - -### [Read the docs](https://rooyca.github.io/obsidian-api-request/) - -## ✅ To-do - -- [ ] Translate documentation -- [x] Data re-usage (`{{ls.UUID>JSONPath}}` syntax, where `ls` stands for `localStorage`) -- [x] Support for comments using `#` or `//` syntax -- [ ] Inline query from response -- [ ] Add tests (!!!) -- [ ] Re-implement `repeat` flag (repeat requests X times or every X seconds) -- [ ] Re-implement `properties` flag (specifies the frontmatter properties to update with the response) - -## ❤️ Sponsors +## ❤️ 赞助商 -## ✍️ Feedback and Contributions +## ✍️ 反馈和贡献 -If you encounter any issues or have feedback on the plugin, feel free to open an issue on the [GitHub repository](https://github.com/Rooyca/obsidian-api-request). Contributions are also welcome! \ No newline at end of file +如果您遇到任何问题或对插件有反馈,请随时在 [GitHub 仓库](https://github.com/Rooyca/obsidian-api-request)上提出问题。 + +也欢迎贡献! diff --git a/docs/docs/en/codeblocks.md b/docs/docs/en/codeblocks.md index 9b5e421..cc2d2b3 100644 --- a/docs/docs/en/codeblocks.md +++ b/docs/docs/en/codeblocks.md @@ -1,28 +1,50 @@ # 👨🏻‍💻 Codeblocks -The `codeblock` is a versatile block that can be used to write code in different languages. In this case, we will use it to make API requests. +The `codeblock` is a versatile block that can be used to make API requests directly from your notes. This guide covers all available flags and how to use them effectively and securely. ## 🏳️ Flags -Flags are the way to specify the parameters of our request. +Flags are the way to specify the parameters of our request. All flags are **case-insensitive**. -| Flag | Default | -| ------------| ---------| -| [url](#url) | | -| [method](#method) | GET | -| [body](#body) | | -| [headers](#headers) | | -| [show](#show) | ALL | -| [req-uuid](#req-uuid) | req-general | -| [hidden](#hidden) | FALSE | -| [disabled](#disabled) | | -| [save-as](#save-as) | | -| [auto-update](#auto-update) | FALSE | -| [format](#format) | | -| [properties](#properties) | | +| Flag | Default | Required | Description | +| ------------| ---------| -------- | ----------- | +| [url](#url) | | ✅ Yes | The API endpoint to request | +| [method](#method) | GET | No | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) | +| [body](#body) | | No | Request body (JSON format) | +| [headers](#headers) | | No | Request headers (JSON format) | +| [show](#show) | ALL | No | JSONPath to extract specific data | +| [req-uuid](#req-uuid) | req-general | No | Unique ID for caching | +| [hidden](#hidden) | FALSE | No | Hide the output | +| [disabled](#disabled) | | No | Disable the request | +| [save-as](#save-as) | | No | Save response to file | +| [auto-update](#auto-update) | FALSE | No | Always fetch fresh data | +| [format](#format) | | No | Custom output format | +| [properties](#properties) | | No | Update frontmatter properties | --- +## 🔒 Security Considerations + +!!! danger "Important Security Guidelines" + - **Always use HTTPS**: Use `https://` URLs to ensure encrypted communication + - **Protect API Keys**: Store sensitive tokens in global variables, never hardcode them in notes + - **Validate Inputs**: The plugin validates all inputs, but only connect to trusted APIs + - **Review Cached Data**: Regularly clear old cached responses from Settings + +### Input Validation + +All user inputs are automatically validated: + +- **URLs**: Only `http://` and `https://` protocols are allowed +- **UUIDs**: Sanitized to alphanumeric, hyphens, and underscores only +- **File Paths**: Directory traversal (`..`) and absolute paths are blocked +- **JSONPath**: Expressions are validated to prevent script injection +- **Format Strings**: HTML is sanitized to prevent XSS attacks + +--- + +## 📖 Variables & Data Reuse + ### LocalStorage & Variables API responses can be stored in `localStorage` and reused in other codeblocks or notes. To store a response, you must assign it a unique identifier using the `req-uuid` flag. @@ -33,36 +55,99 @@ You can access stored responses using the following syntax: {{ls.UUID>JSONPath}} ``` -* `UUID`: The unique identifier defined in the `req-uuid` flag. -* `JSONPath`: The path to the specific data you want from the response. +* `UUID`: The unique identifier defined in the `req-uuid` flag (without the `req-` prefix) +* `JSONPath`: The path to the specific data you want from the response **Example:** -If you have a request with `req-uuid: user`, you can access the user’s name like this: +If you have a request with `req-uuid: user`, you can access the user's name like this: ``` {{ls.user>$.name}} ``` +!!! info "Security Note" + UUIDs are automatically sanitized. Only alphanumeric characters, hyphens, and underscores are allowed. + --- -You can also reference variables defined in the note's **frontmatter** using: +### Frontmatter Variables + +You can reference variables defined in the note's **frontmatter** using: ``` {{this.variableName}} ``` +**Example:** + +Frontmatter: +```yaml +--- +userId: 12345 +title: "My Note" +--- +``` + +Usage in request: +~~~markdown +```req +url: https://api.example.com/user/{{this.userId}} +``` +~~~ + +!!! warning "Security Warning" + Avoid storing sensitive API keys in frontmatter. Use global variables instead. + --- -For **global variables**, you can define them in the plugin settings. These are saved in `localStorage` and can be accessed with: +### Global Variables + +Define reusable variables in plugin settings (Settings → APIRequest → Global variables). These are stored securely and can be accessed with: ``` -{{ls.variableName}} +{{VARIABLE_NAME}} ``` +**Example:** + +1. In plugin settings, add: + - Key: `API_KEY` + - Value: `your-secret-key` + +2. In your request: + +~~~markdown +```req +url: https://api.example.com/data +headers: {"Authorization": "Bearer {{API_KEY}}"} +``` +~~~ + +!!! tip "Best Practice" + Store all API keys and tokens as global variables to keep your notes secure and portable. + +--- + +### Special Variables + +- `{{this.file.name}}` - Current file's basename (without extension) + +--- + +## Flag Details + ### url -Is the only **required** flag. It specifies the endpoint of the request. +The only **required** flag. It specifies the endpoint of the API request. +**Syntax:** +~~~markdown +```req +url: https://api.example.com/endpoint +``` +~~~ + +**With variables:** ~~~markdown ```req # this is just a comment @@ -72,16 +157,25 @@ url: https://jsonplaceholder.typicode.com/users/{{this.id}} !!! note "Where `{{this.id}}` is a variable (`id`) defined in the frontmatter." +!!! danger "Security" + Only HTTPS and HTTP URLs are allowed. Other protocols (file://, javascript:, etc.) are blocked for security. + +--- ### method -Specifies the request method. The default value is `GET` and the available methods are: +Specifies the HTTP request method. The default value is `GET`. -- GET +**Available methods:** +- GET (default) - POST - PUT - DELETE +- PATCH +- HEAD +- OPTIONS +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -89,24 +183,40 @@ method: post ``` ~~~ + +--- + ### body -Specifies the body of the request. The default value is an empty object. The data should be in JSON format, separating key and value with a colon plus space (`, `). +Specifies the body of the request. The data should be in JSON format. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts method: post -body: {"title": {{this.filename}}, "body": "bar", "userId": 1} +body: {"title": "{{this.filename}}", "body": "bar", "userId": 1} ``` ~~~ !!! note "Where `{{this.filename}}` is the name of the working file." +**Advanced usage with variables:** +~~~markdown +```req +url: https://api.example.com/create +method: post +body: {"userId": {{this.userId}}, "token": "{{API_TOKEN}}"} +``` +~~~ + +--- + ### headers -Specifies the headers of the request. The default value is an empty object. The data should be in JSON format, separating key and value with a colon plus space (`, `). +Specifies the request headers. The data should be in JSON format. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -115,23 +225,32 @@ headers: {"Content-type": "application/json; charset=UTF-8"} ``` ~~~ +**Using cached responses as headers:** + You can use responses from other requests as headers/body/url/show. For example, if you have a request with `req-uuid: token`, you can use it like this: -~~~makdown +~~~markdown ```req url: https://api.todoist.com/rest/v2/tasks headers: {"Authorization": "Bearer {{ls.token>$.access_token}}"} show: $..content format: - [ ] {} -req-id: todos +req-uuid: todos ``` ~~~ +!!! tip "Common Headers" + - `Content-Type: application/json` - For JSON data + - `Authorization: Bearer TOKEN` - For API authentication + - `Accept: application/json` - To request JSON responses + +--- + ### show -Specifies the response data to display. See [JSONPath examples](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples), or try the online tool by [jsonpath-plus](https://jsonpath-plus.github.io/JSONPath/demo/). - +Specifies which data from the response to display using JSONPath expressions. See [JSONPath examples](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples), or try the online tool by [jsonpath-plus](https://jsonpath-plus.github.io/JSONPath/demo/). +**Simple example:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats @@ -139,8 +258,7 @@ show: $['chess_daily']['last']['rating'] ``` ~~~ -Multiple outputs can be displayed by using `[]`. - +**Multiple outputs using brackets:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats @@ -148,8 +266,7 @@ show: $.chess_daily[last,best].rating ``` ~~~ -Or you can also use `+` to get multiple outputs. - +**Multiple outputs using +:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats @@ -157,8 +274,9 @@ show: $.chess_daily[last,best].rating + $.chess960_daily[last,best].rating ``` ~~~ -Looping over an array is also possible. The following example retrieves the city from all users. +**Looping over arrays:** +Get city from all users: ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -166,8 +284,7 @@ show: $..address.city ``` ~~~ -Looping over a specified number of elements of the array is also possible. - +**Looping over first N elements:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -175,8 +292,7 @@ show: $..[:3].address.city ``` ~~~ -It's also possible to loop over a specified range of indexes of the array. - +**Specific array indexes:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -184,8 +300,9 @@ show: $..[3,2,6].address.city ``` ~~~ -You can access the last element using `(@.length-1)` or just `[-1:]`. +**Last element:** +You can access the last element using `(@.length-1)` or just `[-1:]`: ~~~markdown ```req url: https://api.modrinth.com/v2/project/distanthorizons @@ -193,21 +310,24 @@ show: $.game_versions[(@.length-1)] ``` ~~~ -To access multiple elements at the same time. - +**Multiple properties:** ~~~markdown ```req -url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key=API_KEY&format=json&limit=4 +url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key={{API_KEY}}&format=json&limit=4 show: $..recenttracks.track[0:][streamable,name,artist] ``` ~~~ +!!! info "Security Note" + JSONPath expressions are validated to prevent script injection. Malicious expressions will be blocked. + +--- ### req-uuid -Specifies the unique identifier of the request. This is useful when we want to store the response in `localStorage` and use it in other blocks or notes. - +Specifies the unique identifier for caching the request response in `localStorage`. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 @@ -218,7 +338,9 @@ req-uuid: test-{{this.username}} !!! note "Where `{{this.username}}` is a variable (`username`) defined in the frontmatter." -Stored responses can be accessed using the `req-uuid` (which won't trigger a new request). +**Accessing cached responses:** + +Stored responses can be accessed using the `req-uuid` (which won't trigger a new request): ~~~markdown ```req @@ -227,7 +349,9 @@ req-uuid: name ``` ~~~ -Responses can also be accessed using [dataview](https://blacksmithgu.github.io/dataview/). +**Using with Dataview:** + +Responses can also be accessed using [dataview](https://blacksmithgu.github.io/obsidian-dataview/): ~~~markdown ```dataviewjs @@ -235,22 +359,31 @@ dv.paragraph(localStorage.getItem("req-UUID")) ``` ~~~ -!!! info "Is mandatory to use `req-` before whatever you defined in `req-uuid` flag." +!!! info "Always use `req-` prefix when accessing via localStorage" + When accessing directly through localStorage, use: `localStorage.getItem("req-UUID")` -To remove responses from localStorage, run: +**Removing cached responses:** +From code: ~~~markdown ```dataviewjs localStorage.removeItem("req-name") ``` ~~~ -To remove responses, go to settings and click over the response you want to delete. +From settings: +Go to Settings → APIRequest → Saved API Requests and click on the response you want to delete. + +!!! tip "Cache Management" + Regularly review and clear old cached responses to free up localStorage space. + +--- ### hidden -Executes the code block without displaying its output. +Executes the code block without displaying its output. Useful for background requests that cache data. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 @@ -259,10 +392,16 @@ hidden ``` ~~~ +!!! tip "Use Case" + Great for fetching authentication tokens or other data you want to cache but not display. + +--- + ### disabled -Disables the request. The codeblock won't be executed. +Disables the request. The codeblock won't be executed. Useful for temporarily disabling requests without deleting them. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 @@ -272,10 +411,16 @@ disabled ``` ~~~ +!!! tip "Development Tip" + Use `disabled` during development to prevent hitting API rate limits. + +--- + ### save-as -Specifies the path to save the response. It'll save the entire response. A file extension is required. It won't create directories. +Saves the entire response to a file. A file extension is required. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -283,10 +428,23 @@ save-as: posts/1.json ``` ~~~ +!!! warning "Important" + - File paths are validated for security + - Directory traversal (`..`) is blocked + - Absolute paths are not allowed + - The file path is relative to your vault root + - Directories are NOT created automatically + +!!! tip "File Management" + Create the target directory in your vault before using `save-as`. + +--- + ### auto-update -If present, the codeblock will automatically update the response every time is possible. This is only needed when using the flag `req-uuid`, because the default behavior of the codeblock is to run every time the note is loaded. +Forces the codeblock to fetch fresh data every time, ignoring cached responses. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -296,10 +454,20 @@ save-as: posts/1.json ``` ~~~ +!!! note "When to use" + Use `auto-update` when you need real-time data or when the cached response becomes stale. + +**Without `req-uuid`:** Requests always run fresh by default. +**With `req-uuid`:** Without `auto-update`, cached responses are used. +**With `auto-update`:** Ignores cache and always fetches fresh data. + +--- + ### format -Specifies the format in which the response should be displayed. It can be any string (including `html`). If more than one output is specified, more then one format should be specified, otherwise it'd just render the first output. +Specifies a custom format for displaying the response. Supports HTML and uses `{}` as placeholders. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -308,14 +476,40 @@ format:

{}

{}

``` ~~~ -!!! note "In this example, first `{}` will be replaced with the *title*, and second `{}` will be replaced with the *body*." +!!! note "In this example, the first `{}` will be replaced with the *title*, and the second `{}` will be replaced with the *body*." + +**Advanced formatting:** +~~~markdown +```req +url: https://api.example.com/user/1 +show: $.[name,email,age] +format: **Name:** {} | **Email:** {} | **Age:** {} +``` +~~~ + +**List formatting:** +~~~markdown +```req +url: https://api.todoist.com/rest/v2/tasks +headers: {"Authorization": "Bearer {{TODOIST_TOKEN}}"} +show: $..content +format: - [ ] {} +``` +~~~ + +!!! danger "Security Warning" + Format strings are sanitized to prevent XSS attacks. Script tags, event handlers, and javascript: URIs are automatically removed. + +--- ### properties -!!! warning "To use this flag you need a JSON response and the `show` flag" +Updates frontmatter properties with response data. Requires a JSON response and the `show` flag. -Specifies the frontmatter properties to update with the response. The data should be strings separated by commas. To set internal links use the this `[[..]]` syntax. +**Syntax:** +The data should be property names separated by commas. +**Example:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -323,3 +517,99 @@ show: $.[id,title] properties: id, title ``` ~~~ + +**For internal links, use `[[..]]` syntax:** +~~~markdown +```req +url: https://api.example.com/related +show: $.[id,name] +properties: relatedId, [[relatedNote]] +``` +~~~ + +This will create: +```yaml +--- +relatedId: 123 +relatedNote: "[[Note Name]]" +--- +``` + +!!! tip "Use Case" + Great for automatically populating metadata from API responses. + +--- + +## 💡 Common Patterns + +### Authentication Flow + +1. Get auth token (hidden): +~~~markdown +```req +url: https://api.example.com/auth/login +method: post +body: {"username": "{{this.username}}", "password": "{{this.password}}"} +req-uuid: auth +hidden +``` +~~~ + +2. Use token in subsequent requests: +~~~markdown +```req +url: https://api.example.com/user/data +headers: {"Authorization": "Bearer {{ls.auth>$.token}}"} +``` +~~~ + +### Error Handling + +If a request fails, an error message will be displayed: + +``` +Error: Failed to fetch +``` + +Common errors: + +- **Network Error**: Check your internet connection +- **401 Unauthorized**: Check your API key/token +- **404 Not Found**: Verify the URL is correct +- **Invalid JSONPath**: Check your `show:` expression + +--- + +## 📚 Further Reading + +- [JSONPath Syntax Examples](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples) +- [JSONPath Online Tester](https://jsonpath-plus.github.io/JSONPath/demo/) +- [Use Cases](usecase/index.md) - Real-world examples + +--- + +## ❓ Troubleshooting + +**Request not working?** + +- Check the console (Ctrl+Shift+I) for detailed error messages +- Verify your URL is correct and uses https:// +- Check that all required flags are present +- Ensure your JSONPath expression is valid + +**Cached data not updating?** + +- Remove `req-uuid` to always fetch fresh data +- Or add `auto-update` flag to force refreshing +- Or manually clear cache in Settings + +**Variables not resolving?** + +- Check frontmatter syntax is correct +- Verify global variables are defined in settings +- Ensure you're using the correct variable syntax + +--- + +!!! tip "Need Help?" + If you encounter issues or have questions, please open an issue on [GitHub](https://github.com/Rooyca/obsidian-api-request/issues). diff --git a/docs/docs/en/index.md b/docs/docs/en/index.md index 5826ea1..77bed67 100644 --- a/docs/docs/en/index.md +++ b/docs/docs/en/index.md @@ -1,14 +1,34 @@ # 🔎 Overview -APIRequest (APIR) is a plugin for the note taking app [Obsidian](https://obsidian.md/) that allows you to make requests to apis display the response in your notes. +APIRequest (APIR) is a plugin for the note taking app [Obsidian](https://obsidian.md/) that allows you to make requests to APIs and display the response directly in your notes. ## 🔥 Features -- Perform requests using various methods such as `GET`, `POST`, `PUT`, and `DELETE`. -- Utilize variables from the `front-matter`, global variables or even reuse responses from another codeblocks. -- Save responses in the `localStorage` for convenient access and reuse. -- Disable code blocks as needed to optimize performance. -- Display specific values from responses, providing granular control over the presentation of data. +- **Multiple HTTP Methods**: Perform requests using `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, and `OPTIONS`. +- **Variable Substitution**: Utilize variables from the `front-matter`, global variables, or even reuse responses from other code blocks. +- **Response Caching**: Save responses in `localStorage` for convenient access and reuse across notes. +- **Performance Control**: Disable code blocks as needed to optimize performance. +- **Precise Data Extraction**: Display specific values from responses using JSONPath, providing granular control over data presentation. +- **Security First**: Built-in input validation and sanitization to protect against XSS, injection attacks, and directory traversal. +- **Auto-update**: Automatically refresh cached responses when needed. +- **Format Output**: Custom HTML/text formatting for response data. + +## 🔒 Security Features + +APIRequest implements comprehensive security measures: + +- ✅ **URL Validation**: Only HTTPS and HTTP protocols are allowed +- ✅ **Input Sanitization**: All user inputs are validated and sanitized +- ✅ **XSS Prevention**: HTML output is sanitized to prevent script injection +- ✅ **Path Traversal Protection**: File paths are validated to prevent unauthorized access +- ✅ **Safe JSONPath**: JSONPath expressions are validated before execution +- ✅ **UUID Sanitization**: Request identifiers are sanitized to prevent injection attacks + +!!! warning "Security Best Practices" + - Always use HTTPS URLs when making API requests + - Store API keys in global variables (Settings → APIRequest → Global variables), never in notes + - Only connect to trusted API endpoints + - Regularly review and clear cached responses ## ⚡ How to use @@ -28,3 +48,41 @@ disabled ``` ~~~ +## 📚 Quick Start + +1. **Simple GET Request** + ~~~markdown + ```req + url: https://api.github.com/users/octocat + show: $.name + ``` + ~~~ + +2. **Using Variables** + ~~~markdown + ```req + url: https://api.example.com/user/{{this.userId}} + headers: {"Authorization": "Bearer {{API_TOKEN}}"} + show: $.data.name + ``` + ~~~ + +3. **Caching Responses** + ~~~markdown + ```req + url: https://api.example.com/data + req-uuid: mydata + show: $.result + ``` + ~~~ + +4. **Reusing Cached Data** + ~~~markdown + ```req + url: https://api.example.com/more-data + headers: {"X-Token": "{{ls.mydata>$.token}}"} + ``` + ~~~ + +For detailed documentation on all flags and features, see [Codeblocks](codeblocks.md). + diff --git a/docs/docs/es/codeblocks.md b/docs/docs/es/codeblocks.md index 16e2983..dc60e34 100644 --- a/docs/docs/es/codeblocks.md +++ b/docs/docs/es/codeblocks.md @@ -1,45 +1,181 @@ -# 👨🏻‍💻 Bloque de código +# 👨🏻‍💻 Bloques de Código -El `bloque de código` es un bloque versátil que se puede usar para escribir código en diferentes lenguajes. En este caso, lo usaremos para realizar solicitudes. +El `bloque de código` es un bloque versátil que se puede utilizar para realizar solicitudes API directamente desde tus notas. Esta guía cubre todas las banderas disponibles y cómo usarlas de manera efectiva y segura. ## 🏳️ Banderas -Las banderas son la forma de especificar los parámetros de nuestra solicitud y también el formato en el que queremos nuestra respuesta. +Las banderas son la forma de especificar los parámetros de nuestra solicitud. Todas las banderas **no distinguen entre mayúsculas y minúsculas**. -| Bandera | Valor predeterminado | -| ------------| ---------| -| [url](#url) | | -| [method](#method) | GET | -| [body](#body) | | -| [headers](#headers) | | -| [show](#show) | ALL | -| [req-uuid](#req-uuid) | | -| [disabled](#disabled) | | -| [save-as](#save-as) | | +| Bandera | Por defecto | Requerido | Descripción | +| ------------| ---------| -------- | ----------- | +| [url](#url) | | ✅ Sí | El endpoint de la API a solicitar | +| [method](#method) | GET | No | Método HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) | +| [body](#body) | | No | Cuerpo de la solicitud (formato JSON) | +| [headers](#headers) | | No | Encabezados de la solicitud (formato JSON) | +| [show](#show) | ALL | No | JSONPath para extraer datos específicos | +| [req-uuid](#req-uuid) | req-general | No | ID único para almacenamiento en caché | +| [hidden](#hidden) | FALSE | No | Ocultar la salida | +| [disabled](#disabled) | | No | Deshabilitar la solicitud | +| [save-as](#save-as) | | No | Guardar la respuesta en un archivo | +| [auto-update](#auto-update) | FALSE | No | Siempre obtener datos frescos | +| [format](#format) | | No | Formato de salida personalizado | +| [properties](#properties) | | No | Actualizar propiedades del frontmatter | -### url +--- -Es la única bandera **obligatoria**. Especifica la URL de la solicitud. Se pueden utilizar variables definidas en el `frontmatter`. +## 🔒 Consideraciones de Seguridad + +!!! danger "Directrices de Seguridad Importantes" + - **Siempre usa HTTPS**: Usa URLs `https://` para asegurar comunicación cifrada + - **Protege las Claves API**: Almacena tokens sensibles en variables globales, nunca los codifiques directamente en las notas + - **Valida las Entradas**: El plugin valida todas las entradas, pero solo conéctate a APIs de confianza + - **Revisa los Datos en Caché**: Limpia regularmente las respuestas antiguas en caché desde la Configuración + +### Validación de Entradas + +Todas las entradas del usuario se validan automáticamente: + +- **URLs**: Solo se permiten los protocolos `http://` y `https://` +- **UUIDs**: Sanitizados solo a alfanuméricos, guiones y guiones bajos +- **Rutas de Archivos**: Se bloquean el recorrido de directorios (`..`) y las rutas absolutas +- **JSONPath**: Las expresiones se validan para prevenir inyección de scripts +- **Cadenas de Formato**: El HTML se sanitiza para prevenir ataques XSS + +--- + +## 📖 Variables y Reutilización de Datos + +### LocalStorage y Variables + +Las respuestas de la API se pueden almacenar en `localStorage` y reutilizar en otros bloques de código o notas. Para almacenar una respuesta, debes asignarle un identificador único usando la bandera `req-uuid`. + +Puedes acceder a las respuestas almacenadas usando la siguiente sintaxis: + +``` +{{ls.UUID>JSONPath}} +``` + +* `UUID`: El identificador único definido en la bandera `req-uuid` (sin el prefijo `req-`) +* `JSONPath`: La ruta a los datos específicos que deseas de la respuesta + +**Ejemplo:** +Si tienes una solicitud con `req-uuid: user`, puedes acceder al nombre del usuario así: + +``` +{{ls.user>$.name}} +``` + +!!! info "Nota de Seguridad" + Los UUIDs se sanitizan automáticamente. Solo se permiten caracteres alfanuméricos, guiones y guiones bajos. + +--- + +### Variables del Frontmatter + +Puedes hacer referencia a variables definidas en el **frontmatter** de la nota usando: + +``` +{{this.variableName}} +``` + +**Ejemplo:** + +Frontmatter: +```yaml +--- +userId: 12345 +title: "Mi Nota" +--- +``` + +Uso en la solicitud: +~~~markdown +```req +url: https://api.example.com/user/{{this.userId}} +``` +~~~ + +!!! warning "Advertencia de Seguridad" + Evita almacenar claves API sensibles en el frontmatter. Usa variables globales en su lugar. + +--- + +### Variables Globales + +Define variables reutilizables en la configuración del plugin (Configuración → APIRequest → Variables globales). Estas se almacenan de forma segura y se pueden acceder con: + +``` +{{VARIABLE_NAME}} +``` + +**Ejemplo:** + +1. En la configuración del plugin, agrega: + - Clave: `API_KEY` + - Valor: `your-secret-key` + +2. En tu solicitud: ~~~markdown ```req -# un comentario +url: https://api.example.com/data +headers: {"Authorization": "Bearer {{API_KEY}}"} +``` +~~~ + +!!! tip "Mejor Práctica" + Almacena todas las claves API y tokens como variables globales para mantener tus notas seguras y portables. + +--- + +### Variables Especiales + +- `{{this.file.name}}` - Nombre base del archivo actual (sin extensión) + +--- + +## Detalles de las Banderas + +### url + +La única bandera **requerida**. Especifica el endpoint de la solicitud API. + +**Sintaxis:** +~~~markdown +```req +url: https://api.example.com/endpoint +``` +~~~ + +**Con variables:** +~~~markdown +```req +# esto es solo un comentario url: https://jsonplaceholder.typicode.com/users/{{this.id}} ``` ~~~ !!! note "Donde `{{this.id}}` es una variable (`id`) definida en el frontmatter." +!!! danger "Seguridad" + Solo se permiten URLs HTTPS y HTTP. Otros protocolos (file://, javascript:, etc.) están bloqueados por seguridad. + +--- ### method -Especifica el método de solicitud. El valor predeterminado es `GET` y los valores disponibles son: +Especifica el método de solicitud HTTP. El valor por defecto es `GET`. -- GET +**Métodos disponibles:** +- GET (por defecto) - POST - PUT - DELETE +- PATCH +- HEAD +- OPTIONS +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -47,24 +183,39 @@ method: post ``` ~~~ +--- + ### body -Especifica el cuerpo de la solicitud. El valor predeterminado es un objeto vacío. Los datos deben estar en formato JSON separando las claves y valores con dos puntos y espacio. Se pueden utilizar variables definidas en el `frontmatter`. +Especifica el cuerpo de la solicitud. Los datos deben estar en formato JSON. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts method: post -body: {"title": {{this.title}}, "body": "bar", "userId": 1} +body: {"title": "{{this.filename}}", "body": "bar", "userId": 1} ``` ~~~ -!!! note "Donde `{{this.title}}` es una variable (`title`) definida en el frontmatter." +!!! note "Donde `{{this.filename}}` es el nombre del archivo de trabajo." + +**Uso avanzado con variables:** +~~~markdown +```req +url: https://api.example.com/create +method: post +body: {"userId": {{this.userId}}, "token": "{{API_TOKEN}}"} +``` +~~~ + +--- ### headers -Especifica los encabezados de la solicitud. El valor predeterminado es un objeto vacío. Los datos deben estar en formato JSON separando las claves y valores con dos puntos y espacio. Se pueden utilizar variables definidas en el `frontmatter`. +Especifica los encabezados de la solicitud. Los datos deben estar en formato JSON. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -73,10 +224,32 @@ headers: {"Content-type": "application/json; charset=UTF-8"} ``` ~~~ +**Usando respuestas en caché como encabezados:** + +Puedes usar respuestas de otras solicitudes como encabezados/cuerpo/url/show. Por ejemplo, si tienes una solicitud con `req-uuid: token`, puedes usarla así: + +~~~markdown +```req +url: https://api.todoist.com/rest/v2/tasks +headers: {"Authorization": "Bearer {{ls.token>$.access_token}}"} +show: $..content +format: - [ ] {} +req-uuid: todos +``` +~~~ + +!!! tip "Encabezados Comunes" + - `Content-Type: application/json` - Para datos JSON + - `Authorization: Bearer TOKEN` - Para autenticación API + - `Accept: application/json` - Para solicitar respuestas JSON + +--- + ### show -Especifica los datos de respuesta que se van a mostrar. Ver [ejemplos de JSONPath](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples), o prueba la herramienta online de [jsonpath-plus](https://jsonpath-plus.github.io/JSONPath/demo/). +Especifica qué datos de la respuesta mostrar usando expresiones JSONPath. Ver [ejemplos de JSONPath](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples), o prueba la herramienta en línea de [jsonpath-plus](https://jsonpath-plus.github.io/JSONPath/demo/). +**Ejemplo simple:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats @@ -84,8 +257,7 @@ show: $['chess_daily']['last']['rating'] ``` ~~~ -Se pueden mostrar múltiples resultados usando `[]`. - +**Múltiples salidas usando corchetes:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats @@ -93,8 +265,17 @@ show: $.chess_daily[last,best].rating ``` ~~~ -También es posible iterar sobre un arreglo. El siguiente ejemplo muestra la ciudad de todos los usuarios. +**Múltiples salidas usando +:** +~~~markdown +```req +url: https://api.chess.com/pub/player/hikaru/stats +show: $.chess_daily[last,best].rating + $.chess960_daily[last,best].rating +``` +~~~ +**Iterando sobre arrays:** + +Obtener ciudad de todos los usuarios: ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -102,8 +283,7 @@ show: $..address.city ``` ~~~ -También es posible iterar sobre un número especificado de elementos del arreglo. - +**Iterando sobre los primeros N elementos:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -111,8 +291,7 @@ show: $..[:3].address.city ``` ~~~ -También es posible iterar sobre un rango especificado de índices del arreglo. - +**Índices específicos del array:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users @@ -120,8 +299,9 @@ show: $..[3,2,6].address.city ``` ~~~ -Puedes acceder al último elemento usando `(@.length-1)` o simplemente `[-1:]`. +**Último elemento:** +Puedes acceder al último elemento usando `(@.length-1)` o simplemente `[-1:]`: ~~~markdown ```req url: https://api.modrinth.com/v2/project/distanthorizons @@ -129,62 +309,98 @@ show: $.game_versions[(@.length-1)] ``` ~~~ -Para acceder a multiples resultados podemos usar: - +**Múltiples propiedades:** ~~~markdown ```req -url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key=API_KEY&format=json&limit=4 +url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key={{API_KEY}}&format=json&limit=4 show: $..recenttracks.track[0:][streamable,name,artist] ``` ~~~ +!!! info "Nota de Seguridad" + Las expresiones JSONPath se validan para prevenir inyección de scripts. Las expresiones maliciosas serán bloqueadas. + +--- + ### req-uuid -Especifica el ID con la que se almacenará la solicitud. Esto es útil cuando queremos almacenar la respuesta en `localStorage` y usarla en otros bloques o notas. - +Especifica el identificador único para almacenar en caché la respuesta de la solicitud en `localStorage`. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 show: $.name -req-uuid: name +req-uuid: test-{{this.username}} ``` ~~~ -Las respuestas almacenadas se pueden ver usando el `req-uuid` con la bandera `disabled` (que no activará una nueva solicitud). +!!! note "Donde `{{this.username}}` es una variable (`username`) definida en el frontmatter." + +**Accediendo a respuestas en caché:** + +Las respuestas almacenadas se pueden acceder usando el `req-uuid` (lo cual no activará una nueva solicitud): ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 req-uuid: name -disabled ``` ~~~ -Las respuestas también se pueden ver usando [dataview](https://blacksmithgu.github.io/dataview/). +**Usando con Dataview:** + +Las respuestas también se pueden acceder usando [dataview](https://blacksmithgu.github.io/obsidian-dataview/): ~~~markdown -```dataview -dv.paragraph(localStorage.getItem("req-name")) +```dataviewjs +dv.paragraph(localStorage.getItem("req-UUID")) ``` ~~~ -!!! info "Es obligatorio usar `req-` antes de lo que sea que hayas definido en la bandera `req-uuid`." +!!! info "Siempre usa el prefijo `req-` cuando accedas vía localStorage" + Al acceder directamente a través de localStorage, usa: `localStorage.getItem("req-UUID")` -Para eliminar respuestas de localStorage, ejecuta: +**Eliminando respuestas en caché:** +Desde código: ~~~markdown -```dataview +```dataviewjs localStorage.removeItem("req-name") ``` ~~~ -Para eliminar todas las respuestas, ve a configuraciones y haz clic sobre la respuesta que quieras eliminar. +Desde configuración: +Ve a Configuración → APIRequest → Solicitudes API Guardadas y haz clic en la respuesta que deseas eliminar. + +!!! tip "Gestión de Caché" + Revisa y limpia regularmente las respuestas antiguas en caché para liberar espacio en localStorage. + +--- + +### hidden + +Ejecuta el bloque de código sin mostrar su salida. Útil para solicitudes en segundo plano que almacenan datos en caché. + +**Ejemplo:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/users/1 +req-uuid: name +hidden +``` +~~~ + +!!! tip "Caso de Uso" + Excelente para obtener tokens de autenticación u otros datos que deseas almacenar en caché pero no mostrar. + +--- ### disabled -Deshabilita la solicitud. El codeblock no se ejecutará. +Deshabilita la solicitud. El bloque de código no se ejecutará. Útil para deshabilitar temporalmente solicitudes sin eliminarlas. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 @@ -194,10 +410,16 @@ disabled ``` ~~~ +!!! tip "Consejo de Desarrollo" + Usa `disabled` durante el desarrollo para evitar alcanzar los límites de tasa de la API. + +--- + ### save-as -Especifica la ruta para guardar la respuesta. Guardará toda la respuesta. Se requiere una extensión de archivo. No creará directorios. +Guarda la respuesta completa en un archivo. Se requiere una extensión de archivo. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -205,10 +427,23 @@ save-as: posts/1.json ``` ~~~ +!!! warning "Importante" + - Las rutas de archivo se validan por seguridad + - Se bloquea el recorrido de directorios (`..`) + - No se permiten rutas absolutas + - La ruta del archivo es relativa a la raíz de tu bóveda + - Los directorios NO se crean automáticamente + +!!! tip "Gestión de Archivos" + Crea el directorio de destino en tu bóveda antes de usar `save-as`. + +--- + ### auto-update -El codeblock se actualizará de manera automatica cada que sea posible. Esto solo es necesario cuando la bandera `req-uuid` está precente, porque el comportamiento predeterminado del codeblock es ejecutarse cada vez que se carga la nota. +Fuerza al bloque de código a obtener datos frescos cada vez, ignorando las respuestas en caché. +**Ejemplo:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 @@ -216,4 +451,171 @@ req-uuid: firstPost auto-update save-as: posts/1.json ``` -~~~ \ No newline at end of file +~~~ + +!!! note "Cuándo usar" + Usa `auto-update` cuando necesites datos en tiempo real o cuando la respuesta en caché se vuelva obsoleta. + +**Sin `req-uuid`:** Las solicitudes siempre se ejecutan frescas por defecto. +**Con `req-uuid`:** Sin `auto-update`, se usan las respuestas en caché. +**Con `auto-update`:** Ignora el caché y siempre obtiene datos frescos. + +--- + +### format + +Especifica un formato personalizado para mostrar la respuesta. Admite HTML y usa `{}` como marcadores de posición. + +**Ejemplo:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/posts/1 +show: $.[title,body] +format:

{}

{}

+``` +~~~ + +!!! note "En este ejemplo, el primer `{}` será reemplazado con el *título*, y el segundo `{}` será reemplazado con el *cuerpo*." + +**Formato avanzado:** +~~~markdown +```req +url: https://api.example.com/user/1 +show: $.[name,email,age] +format: **Nombre:** {} | **Email:** {} | **Edad:** {} +``` +~~~ + +**Formato de lista:** +~~~markdown +```req +url: https://api.todoist.com/rest/v2/tasks +headers: {"Authorization": "Bearer {{TODOIST_TOKEN}}"} +show: $..content +format: - [ ] {} +``` +~~~ + +!!! danger "Advertencia de Seguridad" + Las cadenas de formato se sanitizan para prevenir ataques XSS. Las etiquetas de script, manejadores de eventos y URIs javascript: se eliminan automáticamente. + +--- + +### properties + +Actualiza las propiedades del frontmatter con datos de la respuesta. Requiere una respuesta JSON y la bandera `show`. + +**Sintaxis:** +Los datos deben ser nombres de propiedades separados por comas. + +**Ejemplo:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/posts/1 +show: $.[id,title] +properties: id, title +``` +~~~ + +**Para enlaces internos, usa la sintaxis `[[..]]`:** +~~~markdown +```req +url: https://api.example.com/related +show: $.[id,name] +properties: relatedId, [[relatedNote]] +``` +~~~ + +Esto creará: +```yaml +--- +relatedId: 123 +relatedNote: "[[Note Name]]" +--- +``` + +!!! tip "Caso de Uso" + Excelente para poblar automáticamente metadatos desde respuestas API. + +--- + +## 💡 Patrones Comunes + +### Flujo de Autenticación + +1. Obtener token de autenticación (oculto): + +~~~markdown +```req +url: https://api.example.com/auth/login +method: post +body: {"username": "{{this.username}}", "password": "{{this.password}}"} +req-uuid: auth +hidden +``` +~~~ + +2. Usar el token en solicitudes subsecuentes: + +~~~markdown +```req +url: https://api.example.com/user/data +headers: {"Authorization": "Bearer {{ls.auth>$.token}}"} +``` +~~~ + +### Manejo de Errores + +Si una solicitud falla, se mostrará un mensaje de error: + +``` +Error: Failed to fetch +``` + +Errores comunes: +- **Error de Red**: Verifica tu conexión a internet +- **401 No Autorizado**: Verifica tu clave/token API +- **404 No Encontrado**: Verifica que la URL sea correcta +- **JSONPath Inválido**: Verifica tu expresión `show:` + +### Consejos de Rendimiento + +1. **Almacena en caché las respuestas** - Usa `req-uuid` para datos que no cambian a menudo +2. **Usa `disabled`** - Deshabilita temporalmente solicitudes costosas durante el desarrollo +3. **Usa `hidden`** - Oculta la salida para la obtención de datos en segundo plano + +--- + +## 📚 Lecturas Adicionales + +- [Ejemplos de Sintaxis JSONPath](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples) +- [Probador en Línea de JSONPath](https://jsonpath-plus.github.io/JSONPath/demo/) +- [Casos de Uso](usecase/index.md) - Ejemplos del mundo real + +--- + +## ❓ Solución de Problemas + +**¿La solicitud no funciona?** + +- Verifica la consola (Ctrl+Shift+I) para mensajes de error detallados +- Verifica que tu URL sea correcta y use https:// +- Verifica que todas las banderas requeridas estén presentes +- Asegúrate de que tu expresión JSONPath sea válida + +**¿Los datos en caché no se actualizan?** + +- Elimina `req-uuid` para siempre obtener datos frescos +- O agrega la bandera `auto-update` para forzar la actualización +- O limpia manualmente el caché en Configuración + +**¿Las variables no se resuelven?** + +- Verifica que la sintaxis del frontmatter sea correcta +- Verifica que las variables globales estén definidas en la configuración +- Asegúrate de estar usando la sintaxis correcta de variables + +--- + +!!! tip "¿Necesitas Ayuda?" + Si encuentras problemas o tienes preguntas, por favor abre un issue en [GitHub](https://github.com/Rooyca/obsidian-api-request/issues). diff --git a/docs/docs/es/index.md b/docs/docs/es/index.md index d2dbd93..208ffdd 100644 --- a/docs/docs/es/index.md +++ b/docs/docs/es/index.md @@ -1,14 +1,34 @@ -# 🔎 APIRequest +# 🔎 Descripción General -APIRequest (APIR) es un plugin para [Obsidian](https://obsidian.md/) que te permite realizar solicitudes HTTP y mostrar la respuesta en tus notas. +APIRequest (APIR) es un plugin para la aplicación de toma de notas [Obsidian](https://obsidian.md/) que te permite realizar solicitudes a APIs y mostrar la respuesta directamente en tus notas. ## 🔥 Características -- Realiza solicitudes HTTP utilizando varios métodos como `GET`, `POST`, `PUT` y `DELETE`. -- Utiliza variables del front-matter dentro de bloques de código. -- Guarda respuestas en `localStorage` para un acceso y reutilización convenientes. -- Desactiva bloques de código según sea necesario para optimizar el rendimiento. -- Muestra valores específicos de las respuestas, proporcionando un control detallado sobre la presentación de datos. +- **Múltiples Métodos HTTP**: Realiza solicitudes usando `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD` y `OPTIONS`. +- **Sustitución de Variables**: Utiliza variables del `front-matter`, variables globales o incluso reutiliza respuestas de otros bloques de código. +- **Caché de Respuestas**: Guarda respuestas en `localStorage` para acceso y reutilización conveniente entre notas. +- **Control de Rendimiento**: Desactiva bloques de código según sea necesario para optimizar el rendimiento. +- **Extracción Precisa de Datos**: Muestra valores específicos de las respuestas usando JSONPath, proporcionando control granular sobre la presentación de datos. +- **Seguridad Primero**: Validación y sanitización de entradas incorporada para proteger contra XSS, ataques de inyección y directory traversal. +- **Auto-actualización**: Actualiza automáticamente respuestas en caché cuando sea necesario. +- **Formato de Salida**: Formato HTML/texto personalizado para datos de respuesta. + +## 🔒 Características de Seguridad + +APIRequest implementa medidas de seguridad completas: + +- ✅ **Validación de URL**: Solo se permiten protocolos HTTPS y HTTP +- ✅ **Sanitización de Entradas**: Todas las entradas de usuario son validadas y sanitizadas +- ✅ **Prevención de XSS**: La salida HTML es sanitizada para prevenir inyección de scripts +- ✅ **Protección contra Directory Traversal**: Las rutas de archivos son validadas para prevenir acceso no autorizado +- ✅ **JSONPath Seguro**: Las expresiones JSONPath son validadas antes de la ejecución +- ✅ **Sanitización de UUID**: Los identificadores de solicitud son sanitizados para prevenir ataques de inyección + +!!! warning "Mejores Prácticas de Seguridad" + - Siempre usa URLs HTTPS al realizar solicitudes API + - Almacena claves API en variables globales (Configuración → APIRequest → Variables globales), nunca en notas + - Revisa y limpia regularmente respuestas en caché (Configuración → APIRequest → Solicitudes API Guardadas) + - Solo conéctate a endpoints API de confianza ## ⚡ Cómo usar @@ -23,7 +43,49 @@ method: post body: {"id":1} headers: {"Accept": "application/json"} show: $.id -req-uuid: id-persona +req-uuid: IDpersona disabled ``` -~~~ \ No newline at end of file +~~~ + +## 📚 Inicio Rápido + +1. **Solicitud GET Simple** + +~~~markdown +```req +url: https://api.github.com/users/octocat +show: $.name +``` +~~~ + +2. **Usando Variables** + +~~~markdown +```req +url: https://api.example.com/user/{{this.userId}} +headers: {"Authorization": "Bearer {{API_TOKEN}}"} +show: $.data.name +``` +~~~ + +3. **Almacenando Respuestas en Caché** + +~~~markdown +```req +url: https://api.example.com/data +req-uuid: mydata +show: $.result +``` +~~~ + +4. **Reutilizando Datos en Caché** + +~~~markdown +```req +url: https://api.example.com/more-data +headers: {"X-Token": "{{ls.mydata>$.token}}"} +``` +~~~ + +Para documentación detallada sobre todas las banderas y características, consulta [Bloques de código](codeblocks.md). diff --git a/docs/docs/es/usecase/index.md b/docs/docs/es/usecase/index.md index 2226840..9d0a435 100644 --- a/docs/docs/es/usecase/index.md +++ b/docs/docs/es/usecase/index.md @@ -1,9 +1,34 @@ -# Ejemplos de uso +# Casos de uso -A collection of use cases for this plugin. **If you have a one, please share it with us.** -Una colección ejemplos de uso para este plugin. **Si tienes uno, por favor compártelo con nosotros.** +Una colección de casos de uso para este complemento. **Si tienes uno, por favor compártelo con nosotros.** -## Ver el precio de BITCOIN (o cualquier criptomoneda) +## Uso de respuestas en línea con [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) + +Primero, haz una solicitud y almacena la respuesta usando `req-uuid`: + +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/comments/1 +req-uuid: test +hidden +``` +~~~ + +A continuación, con **DataviewJS** y las consultas JavaScript en línea habilitadas, puedes acceder a los datos guardados de esta manera: + +```markdown +El correo electrónico es `$=dv.el("span", JSON.parse(localStorage.getItem("req-test")).email)` +y el ID es `$=dv.el("span", JSON.parse(localStorage.getItem("req-test")).id, { cls: "mod-warning" })` +``` + +Esto recupera el correo electrónico y el ID de la respuesta guardada (el prefijo `req-` siempre es requerido). +Aquí, también estamos añadiendo una clase personalizada a la segunda consulta en línea. + +La salida renderizada se verá así: + +> El correo electrónico es [Eliseo@gardner.biz](mailto:Eliseo@gardner.biz) y el ID es 1 + +## Consultar el precio de BITCOIN (o cualquier criptomoneda) ~~~makdown ```req @@ -23,7 +48,7 @@ show: $.main.temp ``` ~~~ -## Buscar peliculas +## Buscar películas ~~~makdown ```req @@ -32,25 +57,27 @@ show: $.results[0:].title ``` ~~~ -!!! info "Nota el uso de `{{this.title}}`. Esta es una característica que te permite pasar propiedades del front-matter." +!!! info "Observa el uso de `{{this.title}}`. Esta es una característica que te permite pasar propiedades del front-matter." -## Obtener más de un resultado +## Renderizar datos -~~~makdown +~~~markdown ```req -url: https://mapi.mobilelegends.com/hero/detail?id={{this.file.name}} +url: https://mapi.mobilelegends.com/hero/detail?id=1 show: $.data[cover_picture,name,type] +format: ![img]({})
Name: {}
Type: {} ``` ~~~ -## Obtener Tareas de [todoist](https://todoist.com/) +## Obtener TAREAS desde [todoist](https://todoist.com/) ~~~makdown ```req url: https://api.todoist.com/rest/v2/tasks headers: {"Authorization": "Bearer YOUR_TOKEN"} show: $..content -req-uuid: todos +format: - [ ] {} +req-id: todos ``` ~~~ @@ -58,4 +85,4 @@ req-uuid: todos ## Tu caso de uso -> **Si deseas compartir tu caso de uso, por favor siéntete libre de abrir una PR o un [Issue](https://github.com/Rooyca/obsidian-api-request/issues/new/choose)** \ No newline at end of file +> **Si quieres compartir tu caso de uso, siéntete libre de abrir un PR o un [Issue](https://github.com/Rooyca/obsidian-api-request/issues/new/choose).** \ No newline at end of file diff --git a/docs/docs/zh/codeblocks.md b/docs/docs/zh/codeblocks.md index ffff817..58ba44f 100644 --- a/docs/docs/zh/codeblocks.md +++ b/docs/docs/zh/codeblocks.md @@ -1,43 +1,181 @@ # 👨🏻‍💻 代码块 -`codeblock` 是一个多功能块,可用于用不同语言编写代码。在本例中,我们将使用它来发出请求。 +`codeblock` 是一个多功能代码块,可用于直接从你的笔记中发送 API 请求。本指南涵盖所有可用的标志以及如何有效且安全地使用它们。 -## 🏳️ Flag +## 🏳️ 标志 -Flag是指定请求参数以及我们想要的响应格式的方式。 +标志是指定请求参数的方式。所有标志都**不区分大小写**。 -| 标志 | 默认 | -| ------------| ---------| -| [url](#url) | | -| [method](#method) | GET | -| [body](#body) | | -| [headers](#headers) | | -| [show](#show) | ALL | -| [req-id](#req-id) | req-general | -| [disabled](#disabled) | | -| [save-as](#save-as) | | +| 标志 | 默认值 | 必需 | 描述 | +| ------------| ---------| -------- | ----------- | +| [url](#url) | | ✅ 是 | 要请求的 API 端点 | +| [method](#method) | GET | 否 | HTTP 方法 (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) | +| [body](#body) | | 否 | 请求体 (JSON 格式) | +| [headers](#headers) | | 否 | 请求头 (JSON 格式) | +| [show](#show) | ALL | 否 | 用于提取特定数据的 JSONPath | +| [req-uuid](#req-uuid) | req-general | 否 | 用于缓存的唯一 ID | +| [hidden](#hidden) | FALSE | 否 | 隐藏输出 | +| [disabled](#disabled) | | 否 | 禁用请求 | +| [save-as](#save-as) | | 否 | 将响应保存到文件 | +| [auto-update](#auto-update) | FALSE | 否 | 总是获取新数据 | +| [format](#format) | | 否 | 自定义输出格式 | +| [properties](#properties) | | 否 | 更新前置元数据属性 | + +--- + +## 🔒 安全注意事项 + +!!! danger "重要安全指南" + - **始终使用 HTTPS**: 使用 `https://` URL 以确保加密通信 + - **保护 API 密钥**: 将敏感令牌存储在全局变量中,永远不要在笔记中硬编码 + - **验证输入**: 插件会验证所有输入,但只连接到受信任的 API + - **检查缓存数据**: 定期从设置中清除旧的缓存响应 + +### 输入验证 + +所有用户输入都会自动验证: + +- **URL**: 只允许 `http://` 和 `https://` 协议 +- **UUID**: 仅清理为字母数字、连字符和下划线 +- **文件路径**: 阻止目录遍历 (`..`) 和绝对路径 +- **JSONPath**: 验证表达式以防止脚本注入 +- **格式字符串**: 清理 HTML 以防止 XSS 攻击 + +--- + +## 📖 变量与数据复用 + +### 本地存储与变量 + +API 响应可以存储在 `localStorage` 中,并在其他代码块或笔记中重用。要存储响应,必须使用 `req-uuid` 标志为其分配唯一标识符。 + +你可以使用以下语法访问存储的响应: + +``` +{{ls.UUID>JSONPath}} +``` + +* `UUID`: 在 `req-uuid` 标志中定义的唯一标识符(不含 `req-` 前缀) +* `JSONPath`: 你想要从响应中获取的特定数据的路径 + +**示例:** +如果你有一个带有 `req-uuid: user` 的请求,你可以这样访问用户的名字: + +``` +{{ls.user>$.name}} +``` + +!!! info "安全说明" + UUID 会自动清理。只允许字母数字字符、连字符和下划线。 + +--- + +### 前置元数据变量 + +你可以使用以下语法引用笔记**前置元数据**中定义的变量: + +``` +{{this.variableName}} +``` + +**示例:** + +前置元数据: +```yaml +--- +userId: 12345 +title: "我的笔记" +--- +``` + +在请求中使用: +~~~markdown +```req +url: https://api.example.com/user/{{this.userId}} +``` +~~~ + +!!! warning "安全警告" + 避免在前置元数据中存储敏感的 API 密钥。请改用全局变量。 + +--- + +### 全局变量 + +在插件设置中定义可重用的变量(设置 → APIRequest → 全局变量)。这些变量会被安全存储,可以通过以下方式访问: + +``` +{{VARIABLE_NAME}} +``` + +**示例:** + +1. 在插件设置中添加: + - 键: `API_KEY` + - 值: `your-secret-key` + +2. 在你的请求中: + +~~~markdown +```req +url: https://api.example.com/data +headers: {"Authorization": "Bearer {{API_KEY}}"} +``` +~~~ + +!!! tip "最佳实践" + 将所有 API 密钥和令牌存储为全局变量,以保持笔记的安全性和可移植性。 + +--- + +### 特殊变量 + +- `{{this.file.name}}` - 当前文件的基本名称(不含扩展名) + +--- + +## 标志详情 ### url -是唯一的**必需**标志。它指定请求的端点。可以使用 `frontmatter` 中定义的变量。 +唯一**必需**的标志。它指定 API 请求的端点。 +**语法:** ~~~markdown ```req +url: https://api.example.com/endpoint +``` +~~~ + +**使用变量:** +~~~markdown +```req +# 这只是一个注释 url: https://jsonplaceholder.typicode.com/users/{{this.id}} ``` ~~~ -!!! note "其中`{{this.id}}`是frontmatter中定义的变量(`id`)。" +!!! note "其中 `{{this.id}}` 是在前置元数据中定义的变量 (`id`)。" + +!!! danger "安全性" + 只允许 HTTPS 和 HTTP URL。出于安全考虑,其他协议(file://、javascript: 等)会被阻止。 + +--- ### method -指定请求方法。默认值为 `GET`,可用值为: +指定 HTTP 请求方法。默认值为 `GET`。 -- GET +**可用方法:** +- GET (默认) - POST - PUT - DELETE +- PATCH +- HEAD +- OPTIONS +**示例:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -45,24 +183,39 @@ method: post ``` ~~~ +--- + ### body -指定请求的正文。默认值为空对象。数据应为 JSON 格式,双引号用冒号和空格分隔键和值。可以使用 `frontmatter` 中定义的变量。 +指定请求体。数据应为 JSON 格式。 +**示例:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts method: post -body: {"title": {{this.title}}, "body": "bar", "userId": 1} +body: {"title": "{{this.filename}}", "body": "bar", "userId": 1} ``` ~~~ -!!! note "其中 `{{this.title}}` 是 frontmatter 中定义的变量(`title`)。" +!!! note "其中 `{{this.filename}}` 是工作文件的名称。" + +**使用变量的高级用法:** +~~~markdown +```req +url: https://api.example.com/create +method: post +body: {"userId": {{this.userId}}, "token": "{{API_TOKEN}}"} +``` +~~~ + +--- ### headers -指定请求的标头。默认值为空对象。数据应为 JSON 格式,双引号将键和值用冒号和空格分隔。可以使用 `frontmatter` 中定义的变量。 +指定请求头。数据应为 JSON 格式。 +**示例:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts @@ -71,145 +224,398 @@ headers: {"Content-type": "application/json; charset=UTF-8"} ``` ~~~ +**使用缓存响应作为请求头:** + +你可以使用其他请求的响应作为 headers/body/url/show。例如,如果你有一个带有 `req-uuid: token` 的请求,你可以这样使用: + +~~~markdown +```req +url: https://api.todoist.com/rest/v2/tasks +headers: {"Authorization": "Bearer {{ls.token>$.access_token}}"} +show: $..content +format: - [ ] {} +req-uuid: todos +``` +~~~ + +!!! tip "常用请求头" + - `Content-Type: application/json` - 用于 JSON 数据 + - `Authorization: Bearer TOKEN` - 用于 API 认证 + - `Accept: application/json` - 请求 JSON 响应 + +--- + ### show -指定要显示的响应数据。使用右箭头 `->` 访问嵌套对象。默认值为 `ALL`。 +使用 JSONPath 表达式指定要显示响应中的哪些数据。查看 [JSONPath 示例](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples),或尝试 [jsonpath-plus](https://jsonpath-plus.github.io/JSONPath/demo/) 在线工具。 +**简单示例:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats -show: chess_daily -> last -> rating +show: $['chess_daily']['last']['rating'] ``` ~~~ -可以通过用逗号分隔来显示多个输出。 - +**使用方括号的多个输出:** ~~~markdown ```req url: https://api.chess.com/pub/player/hikaru/stats -show: chess_daily -> last -> rating, chess_daily -> best -> rating -format:

Last game: {}

Best game: {} -render +show: $.chess_daily[last,best].rating ``` ~~~ -也可以使用 `{..}` 循环遍历数组。以下示例从所有用户中检索城市 (city)。 - +**使用 + 的多个输出:** ~~~markdown ```req -url: https://jsonplaceholder.typicode.com/users -show: {..} -> address -> city +url: https://api.chess.com/pub/player/hikaru/stats +show: $.chess_daily[last,best].rating + $.chess960_daily[last,best].rating ``` ~~~ -也可以使用 `{n..n}` 循环遍历数组中指定数量的元素。 +**循环遍历数组:** +获取所有用户的城市: ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users -show: {0..2} -> address -> city +show: $..address.city ``` ~~~ -也可以使用 `{n-n-n}` 循环遍历数组的指定范围的索引。 - +**循环遍历前 N 个元素:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users -show: {0-2-1} -> address -> city +show: $..[:3].address.city ``` ~~~ -您可以使用 `{-1}` 访问最后一个元素... - -~~~markdown -```req -url:https://api.modrinth.com/v2/project/distanthorizons -show: game_versions -> {-1} -``` -~~~ - -...或者使用 `{len}` 获取数组的长度。 - -~~~markdown -```req -url:https://api.modrinth.com/v2/project/distanthorizons -show: game_versions -> {len} -``` -~~~ - -使用 `{..}` 时,若要同时访问多个元素,请使用 `&` 分隔键,并使用 `.` 访问值。 - +**特定数组索引:** ~~~markdown ```req -url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key=API_KEY&format=json&limit=4 -show: recenttracks -> track -> {..} -> name & artist.#text & streamable -maketable: name, artist, stream +url: https://jsonplaceholder.typicode.com/users +show: $..[3,2,6].address.city ``` ~~~ -### req-id +**最后一个元素:** -指定请求的 ID。默认值为 `req-general`。当我们想要将响应存储在 `localStorage` 中并在其他块或注释中使用它时,这很有用。 +你可以使用 `(@.length-1)` 或只使用 `[-1:]` 访问最后一个元素: +~~~markdown +```req +url: https://api.modrinth.com/v2/project/distanthorizons +show: $.game_versions[(@.length-1)] +``` +~~~ + +**多个属性:** +~~~markdown +```req +url: http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rooyca&api_key={{API_KEY}}&format=json&limit=4 +show: $..recenttracks.track[0:][streamable,name,artist] +``` +~~~ + +!!! info "安全说明" + JSONPath 表达式会被验证以防止脚本注入。恶意表达式将被阻止。 + +--- + +### req-uuid + +指定用于在 `localStorage` 中缓存请求响应的唯一标识符。 + +**示例:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/users/1 +show: $.name +req-uuid: test-{{this.username}} +``` +~~~ + +!!! note "其中 `{{this.username}}` 是在前置元数据中定义的变量 (`username`)。" + +**访问缓存响应:** + +可以使用 `req-uuid` 访问存储的响应(这不会触发新请求): ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 -show: name -req-id: name +req-uuid: name ``` ~~~ -可以使用带有 `disabled` 标志的 `req-id` 访问存储的响应(不会触发新请求)。 +**与 Dataview 一起使用:** + +也可以使用 [dataview](https://blacksmithgu.github.io/obsidian-dataview/) 访问响应: ~~~markdown -```req -url: https://jsonplaceholder.typicode.com/users/1 -req-id: name -disabled +```dataviewjs +dv.paragraph(localStorage.getItem("req-UUID")) ``` ~~~ -也可以使用 [dataview](https://blacksmithgu.github.io/dataview/) 访问响应。 +!!! info "通过 localStorage 访问时始终使用 `req-` 前缀" + 通过 localStorage 直接访问时,使用: `localStorage.getItem("req-UUID")` +**删除缓存响应:** + +从代码中: ~~~markdown -```dataview -dv.paragraph(localStorage.getItem("req-name")) -``` -~~~ - -!!! info "在`req-id`标志中定义的任何内容之前,必须使用`req-`" - -要从 localStorage 中删除响应,请运行: - -~~~markdown -```dataview +```dataviewjs localStorage.removeItem("req-name") ``` ~~~ -要删除所有响应,请转到设置并单击 `Clear ID's` (清除ID) 按钮。 +从设置中: +转到 设置 → APIRequest → 已保存的 API 请求,然后点击你想删除的响应。 -### disabled +!!! tip "缓存管理" + 定期检查并清除旧的缓存响应以释放 localStorage 空间。 -禁用请求。如果指定了 `req-id`,APIR 将在`localStorage`中检查响应。如果未找到,它将发出新请求并存储它。之后,APIR 将使用存储的响应。 +--- +### hidden + +执行代码块但不显示其输出。适用于缓存数据的后台请求。 + +**示例:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/users/1 -show: name -req-id: name +req-uuid: name +hidden +``` +~~~ + +!!! tip "用例" + 非常适合获取身份验证令牌或其他你想缓存但不显示的数据。 + +--- + +### disabled + +禁用请求。代码块不会被执行。适用于临时禁用请求而不删除它们。 + +**示例:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/users/1 +show: $.name +req-uuid: name disabled ``` ~~~ +!!! tip "开发提示" + 在开发期间使用 `disabled` 以防止达到 API 速率限制。 + +--- + ### save-as -指定保存响应的路径。它将保存整个响应。需要文件扩展名。它不会创建目录。 +将整个响应保存到文件。需要文件扩展名。 +**示例:** ~~~markdown ```req url: https://jsonplaceholder.typicode.com/posts/1 save-as: posts/1.json ``` ~~~ + +!!! warning "重要" + - 文件路径会进行安全验证 + - 阻止目录遍历 (`..`) + - 不允许绝对路径 + - 文件路径相对于你的仓库根目录 + - 不会自动创建目录 + +!!! tip "文件管理" + 在使用 `save-as` 之前,在你的仓库中创建目标目录。 + +--- + +### auto-update + +强制代码块每次都获取新数据,忽略缓存响应。 + +**示例:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/posts/1 +req-uuid: firstPost +auto-update +save-as: posts/1.json +``` +~~~ + +!!! note "何时使用" + 当你需要实时数据或缓存响应过时时使用 `auto-update`。 + +**不使用 `req-uuid`:** 请求默认总是获取新数据。 +**使用 `req-uuid`:** 不使用 `auto-update` 时,会使用缓存响应。 +**使用 `auto-update`:** 忽略缓存并总是获取新数据。 + +--- + +### format + +指定显示响应的自定义格式。支持 HTML 并使用 `{}` 作为占位符。 + +**示例:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/posts/1 +show: $.[title,body] +format:

{}

{}

+``` +~~~ + +!!! note "在此示例中,第一个 `{}` 将被替换为 *title*,第二个 `{}` 将被替换为 *body*。" + +**高级格式化:** +~~~markdown +```req +url: https://api.example.com/user/1 +show: $.[name,email,age] +format: **Name:** {} | **Email:** {} | **Age:** {} +``` +~~~ + +**列表格式化:** +~~~markdown +```req +url: https://api.todoist.com/rest/v2/tasks +headers: {"Authorization": "Bearer {{TODOIST_TOKEN}}"} +show: $..content +format: - [ ] {} +``` +~~~ + +!!! danger "安全警告" + 格式字符串会被清理以防止 XSS 攻击。脚本标签、事件处理程序和 javascript: URI 会被自动删除。 + +--- + +### properties + +使用响应数据更新前置元数据属性。需要 JSON 响应和 `show` 标志。 + +**语法:** +数据应为用逗号分隔的属性名称。 + +**示例:** +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/posts/1 +show: $.[id,title] +properties: id, title +``` +~~~ + +**对于内部链接,使用 `[[..]]` 语法:** +~~~markdown +```req +url: https://api.example.com/related +show: $.[id,name] +properties: relatedId, [[relatedNote]] +``` +~~~ + +这将创建: +```yaml +--- +relatedId: 123 +relatedNote: "[[Note Name]]" +--- +``` + +!!! tip "用例" + 非常适合从 API 响应中自动填充元数据。 + +--- + +## 💡 常见模式 + +### 身份验证流程 + +1. 获取身份验证令牌(隐藏): + +~~~markdown +```req +url: https://api.example.com/auth/login +method: post +body: {"username": "{{this.username}}", "password": "{{this.password}}"} +req-uuid: auth +hidden +``` +~~~ + +2. 在后续请求中使用令牌: + +~~~markdown +```req +url: https://api.example.com/user/data +headers: {"Authorization": "Bearer {{ls.auth>$.token}}"} +``` +~~~ + +### 错误处理 + +如果请求失败,将显示错误消息: + +``` +Error: Failed to fetch +``` + +常见错误: +- **网络错误**: 检查你的互联网连接 +- **401 未授权**: 检查你的 API 密钥/令牌 +- **404 未找到**: 验证 URL 是否正确 +- **无效 JSONPath**: 检查你的 `show:` 表达式 + +### 性能提示 + +1. **缓存响应** - 对于不经常更改的数据使用 `req-uuid` +2. **使用 `disabled`** - 在开发期间临时禁用昂贵的请求 +3. **使用 `hidden`** - 隐藏后台数据获取的输出 + +--- + +## 📚 扩展阅读 + +- [JSONPath 语法示例](https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file#syntax-through-examples) +- [JSONPath 在线测试工具](https://jsonpath-plus.github.io/JSONPath/demo/) +- [用例](usecase/index.md) - 真实世界示例 + +--- + +## ❓ 故障排除 + +**请求不工作?** + +- 检查控制台 (Ctrl+Shift+I) 查看详细错误消息 +- 验证你的 URL 是否正确并使用 https:// +- 检查是否存在所有必需的标志 +- 确保你的 JSONPath 表达式有效 + +**缓存数据未更新?** + +- 删除 `req-uuid` 以始终获取新数据 +- 或添加 `auto-update` 标志以强制刷新 +- 或在设置中手动清除缓存 + +**变量未解析?** + +- 检查前置元数据语法是否正确 +- 验证全局变量是否在设置中定义 +- 确保你使用正确的变量语法 + +--- + +!!! tip "需要帮助?" + 如果你遇到问题或有疑问,请在 [GitHub](https://github.com/Rooyca/obsidian-api-request/issues) 上提出问题。 diff --git a/docs/docs/zh/index.md b/docs/docs/zh/index.md index 68f239a..3cacf6a 100644 --- a/docs/docs/zh/index.md +++ b/docs/docs/zh/index.md @@ -1,20 +1,40 @@ # 🔎 概述 -APIRequest (APIR) 是笔记应用 [Obsidian](https://obsidian.md/) 的一个插件,它允许您向 api 或其他来源发出请求并在笔记中显示响应。 +APIRequest (APIR) 是一个用于笔记应用 [Obsidian](https://obsidian.md/) 的插件,允许您向 API 发出请求并直接在笔记中显示响应。 -## 🔥 功能 +## 🔥 功能特性 -- 使用各种方法执行 HTTP 请求,例如 `GET`、`POST`、`PUT` 和 `DELETE`。 -- 在代码块内利用前言中的变量。 -- 将响应保存在 `localStorage` 中,以方便访问和重用。 -- 根据需要禁用代码块以优化性能。 -- 以指定的间隔多次重复请求,促进自动化任务或连续数据检索而无需人工干预。 +- **多种 HTTP 方法**:使用 `GET`、`POST`、`PUT`、`DELETE`、`PATCH`、`HEAD` 和 `OPTIONS` 执行请求。 +- **变量替换**:利用 `front-matter` 中的变量、全局变量,甚至重用其他代码块的响应。 +- **响应缓存**:将响应保存在 `localStorage` 中,方便跨笔记访问和重用。 +- **性能控制**:根据需要禁用代码块以优化性能。 +- **精确数据提取**:使用 JSONPath 显示响应中的特定值,提供对数据呈现的细粒度控制。 +- **安全优先**:内置输入验证和清理,防止 XSS、注入攻击和目录遍历。 +- **自动更新**:在需要时自动刷新缓存的响应。 +- **格式化输出**:为响应数据自定义 HTML/文本格式。 + +## 🔒 安全功能 + +APIRequest 实现了全面的安全措施: + +- ✅ **URL 验证**:仅允许 HTTPS 和 HTTP 协议 +- ✅ **输入清理**:所有用户输入都经过验证和清理 +- ✅ **XSS 防护**:清理 HTML 输出以防止脚本注入 +- ✅ **目录遍历保护**:验证文件路径以防止未授权访问 +- ✅ **安全 JSONPath**:在执行前验证 JSONPath 表达式 +- ✅ **UUID 清理**:清理请求标识符以防止注入攻击 + +!!! warning "安全最佳实践" + - 进行 API 请求时始终使用 HTTPS URL + - 将 API 密钥存储在全局变量中(设置 → APIRequest → 全局变量),而不是笔记中 + - 定期审查和清除缓存的响应(设置 → APIRequest → 已保存的 API 请求) + - 仅连接到受信任的 API 端点 ## ⚡ 如何使用 ### 👨🏻‍💻 代码块 -要使用它,请创建一个代码块,并将语言设置为 `req`。在代码块内,您可以指定`url`、`method`、`body`、`headers` 等。有关更多信息,请参阅[可用标志](codeblocks.md#flags)。 +要使用它,创建一个语言设置为 `req` 的代码块。在代码块内,您可以指定 `url`、`method`、`body`、`headers` 等。有关更多信息,请参阅[可用标志](codeblocks.md#flags)。 ~~~markdown ```req @@ -23,7 +43,49 @@ method: post body: {"id":1} headers: {"Accept": "application/json"} show: $.id -req-uuid: id-persona +req-uuid: IDpersona disabled ``` ~~~ + +## 📚 快速开始 + +1. **简单的 GET 请求** + +~~~markdown +```req +url: https://api.github.com/users/octocat +show: $.name +``` +~~~ + +2. **使用变量** + +~~~markdown +```req +url: https://api.example.com/user/{{this.userId}} +headers: {"Authorization": "Bearer {{API_TOKEN}}"} +show: $.data.name +``` +~~~ + +3. **缓存响应** + +~~~markdown +```req +url: https://api.example.com/data +req-uuid: mydata +show: $.result +``` +~~~ + +4. **重用缓存数据** + +~~~markdown +```req +url: https://api.example.com/more-data +headers: {"X-Token": "{{ls.mydata>$.token}}"} +``` +~~~ + +有关所有标志和功能的详细文档,请参阅[代码块](codeblocks.md)。 diff --git a/docs/docs/zh/usecase/index.md b/docs/docs/zh/usecase/index.md index ef8e14c..f027b5d 100644 --- a/docs/docs/zh/usecase/index.md +++ b/docs/docs/zh/usecase/index.md @@ -1,9 +1,34 @@ -# 用例 +# 使用案例 -此插件的用例集合。 **如果您有,请与我们分享。** +这是该插件的使用案例集合。**如果您有其他使用案例,请与我们分享。** +## 使用内联响应与 [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) 结合 -## 检查比特币(或任何加密货币)价格 +首先,使用 `req-uuid` 发起请求并存储响应: + +~~~markdown +```req +url: https://jsonplaceholder.typicode.com/comments/1 +req-uuid: test +hidden +``` +~~~ + +然后,启用 **DataviewJS** 和内联 JavaScript 查询后,您可以像这样访问保存的数据: + +```markdown +邮箱是 `$=dv.el("span", JSON.parse(localStorage.getItem("req-test")).email)` +ID 是 `$=dv.el("span", JSON.parse(localStorage.getItem("req-test")).id, { cls: "mod-warning" })` +``` + +这将从保存的响应中检索邮箱和 ID(始终需要 `req-` 前缀)。 +在这里,我们还为第二个内联查询添加了自定义类。 + +渲染输出将如下所示: + +> 邮箱是 [Eliseo@gardner.biz](mailto:Eliseo@gardner.biz),ID 是 1 + +## 查询比特币(或任何加密货币)价格 ~~~makdown ```req @@ -14,7 +39,7 @@ show: $.data.rateUsd > 64992.8972508856324769 -## 获取天气 +## 获取天气信息 ~~~makdown ```req @@ -32,18 +57,19 @@ show: $.results[0:].title ``` ~~~ -!!! info "请注意使用 `{{this.title}}`。此功能允许您传递前置属性。" +!!! info "注意 `{{this.title}}` 的使用。这是一个允许您传递 front-matter 属性的功能。" -## 获得多个结果 +## 渲染数据 -~~~makdown +~~~markdown ```req -url: https://mapi.mobilelegends.com/hero/detail?id={{this.file.name}} +url: https://mapi.mobilelegends.com/hero/detail?id=1 show: $.data[cover_picture,name,type] +format: ![img]({})
Name: {}
Type: {} ``` ~~~ -## 从 [todoist](https://todoist.com/) 获取 TODOS +## 从 [todoist](https://todoist.com/) 获取待办事项 ~~~makdown ```req @@ -55,8 +81,8 @@ req-id: todos ``` ~~~ -!!! warning "这将把响应保存在 localStorage 中的键 `req-todos` 下" +!!! warning "这将把响应保存在 localStorage 中,键名为 `req-todos`" -## 您的用例 +## 您的使用案例 -> **如果您想分享您的用例,请随时打开 PR 或 [Issue](https://github.com/Rooyca/obsidian-api-request/issues/new/choose)。** +> **如果您想分享您的使用案例,请随时提交 PR 或创建 [Issue](https://github.com/Rooyca/obsidian-api-request/issues/new/choose)。** diff --git a/manifest.json b/manifest.json index fc36414..16f1a85 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "api-request", "name": "APIRequest", - "version": "2.0.8", + "version": "2.0.9", "minAppVersion": "0.15.0", "description": "Integrate API data into your notes with request caching, variable support, and precise JSON extraction.", "author": "rooyca", diff --git a/package-lock.json b/package-lock.json index 37738ae..fbb9a21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "api-request", - "version": "2.0.8", + "version": "2.0.9", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 4bf93c3..55853aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "api-request", - "version": "2.0.8", + "version": "2.0.9", "description": "Integrate API data into your notes with request caching, variable support, and precise JSON extraction.", "main": "main.js", "scripts": { diff --git a/src/functions/frontmatterUtils.ts b/src/functions/frontmatterUtils.ts index e3c654b..8237d30 100644 --- a/src/functions/frontmatterUtils.ts +++ b/src/functions/frontmatterUtils.ts @@ -1,17 +1,34 @@ -// frontmatter read and parse +/** + * Utilities for reading and parsing frontmatter from markdown files + */ import { parseYaml } from "obsidian"; +/** Regular expression to extract frontmatter content from markdown */ export const FRONTMATTER_REGEX = /^\n*---[^\n]*\n+(?.+?)\n+---.*/s; +/** Type definition for frontmatter content */ export type Frontmatter = string | null | undefined; +/** + * Extracts frontmatter content from markdown text + * + * @param md - The markdown content to extract frontmatter from + * @returns The frontmatter content string, or undefined if not found + */ export function readFrontmatter(md: string) { const result = md.match(FRONTMATTER_REGEX); return result?.groups?.fm; } +/** + * Parses frontmatter YAML content into an object + * + * @param input - The frontmatter content to parse + * @returns Parsed frontmatter object + * @throws Error if frontmatter is not defined or cannot be parsed + */ export function parseFrontmatter(input: Frontmatter) { if (input === undefined || input === null) { throw new Error("Frontmatter not defined."); diff --git a/src/functions/general.ts b/src/functions/general.ts index c2393bc..c201188 100644 --- a/src/functions/general.ts +++ b/src/functions/general.ts @@ -1,5 +1,11 @@ -// Adds the copy button to the code block -// Take from: https://github.com/jdbrice/obsidian-code-block-copy/ +/** + * Adds a copy button to the code block element + * Button copies the specified text to clipboard when clicked + * + * @param el - The HTML element to add the button to + * @param copyThis - The text to copy to clipboard + * @source https://github.com/jdbrice/obsidian-code-block-copy/ + */ export function addBtnCopy(el: HTMLElement, copyThis: string) { const btnCopy = el.createEl("button", { cls: "copy-req", text: "copy" }); btnCopy.addEventListener('click', function () { diff --git a/src/functions/regx.ts b/src/functions/regx.ts index 8c6a20e..8c0bcce 100644 --- a/src/functions/regx.ts +++ b/src/functions/regx.ts @@ -1,20 +1,24 @@ -// Matches a specific pattern inside curly braces: {number1..number2} +/** + * Regular expression utilities for parsing request blocks + */ + +/** Matches a numeric range pattern inside curly braces: {number1..number2} */ export const num_braces_regx = /{(\d+)\.\.(\d+)}/; -// Matches a pattern of digits separated by hyphens, e.g., 1-2-3-4 +/** Matches a pattern of digits separated by hyphens, e.g., 1-2-3-4 */ export const num_hyphen_regx = /(\d+-)+\d+/; -// Matches any sequence of digits, globally. +/** Matches any sequence of digits, globally */ export const nums_rex = /\d+/g; -// Matches anything inside curly braces, non-greedy, globally. +/** Matches anything inside curly braces, non-greedy, globally */ export const in_braces_regx = /{.*?}/g; -// Matches any text inside double curly braces, preceded by "{{this." and followed by "}}" +/** Matches text inside double curly braces, preceded by "{{this." and followed by "}}" */ export const varname_regx = /{{this\.([^{}]*)}}/g; -// Matches "{{this." or "}}" globally +/** Matches "{{this." or "}}" globally - used for removing variable syntax */ export const no_varname_regx = /{{this\.|}}/g; -// Matches "{{KEY}}" globally +/** Matches "{{KEY}}" globally - for global variable replacement */ export const key_regx = /{{(?!this\.)[^{}]*}}/g; \ No newline at end of file diff --git a/src/functions/security.ts b/src/functions/security.ts new file mode 100644 index 0000000..589a6cd --- /dev/null +++ b/src/functions/security.ts @@ -0,0 +1,196 @@ +/** + * Security utilities for input validation and sanitization + */ + +/** + * Validates a URL to ensure it's safe to request + * @param url - The URL to validate + * @returns true if valid, false otherwise + */ +export function isValidUrl(url: string): boolean { + if (!url || typeof url !== 'string') { + return false; + } + + try { + const parsed = new URL(url); + // Only allow http and https protocols + if (!['http:', 'https:'].includes(parsed.protocol)) { + return false; + } + + // Prevent local network access (optional - can be configured) + // Uncomment to prevent requests to localhost/private IPs + // const hostname = parsed.hostname.toLowerCase(); + // if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '0.0.0.0') { + // return false; + // } + + return true; + } catch (e) { + return false; + } +} + +/** + * Validates HTTP method + * @param method - The HTTP method to validate + * @returns true if valid, false otherwise + */ +export function isValidMethod(method: string): boolean { + const allowedMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]; + return allowedMethods.includes(method.toUpperCase()); +} + +/** + * Sanitizes a UUID to prevent injection attacks + * @param uuid - The UUID to sanitize + * @returns Sanitized UUID or null if invalid + */ +export function sanitizeUuid(uuid: string): string | null { + if (!uuid || typeof uuid !== 'string') { + return null; + } + + // Only allow alphanumeric characters, hyphens, and underscores + const sanitized = uuid.replace(/[^a-zA-Z0-9\-_]/g, ''); + + // Limit length to prevent storage issues + if (sanitized.length > 100) { + return sanitized.substring(0, 100); + } + + return sanitized || null; +} + +/** + * Validates JSONPath expression to prevent malicious code execution + * @param jsonPath - The JSONPath expression to validate + * @returns true if valid, false otherwise + */ +export function isValidJsonPath(jsonPath: string): boolean { + if (!jsonPath || typeof jsonPath !== 'string') { + return false; + } + + // Check for potential script injection + const dangerousPatterns = [ + /