feat: OnlyOffice Standalone integration with S3 direct URLs

 ЧТО СДЕЛАНО:
- Поднят новый standalone OnlyOffice Document Server (порт 8083)
- Настроен Nginx для доступа через office.clientright.ru:9443
- Создан open_file_v3_standalone.php для работы с новым OnlyOffice
- Реализована поддержка прямых S3 URL (bucket публичный)
- Добавлен s3_proxy.php с поддержкой Range requests
- Создан onlyoffice_callback.php для сохранения (базовая версия)
- Файлы успешно открываются и загружаются!

⚠️ TODO (на завтра):
- Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3
- Добавить Redis маппинг documentKey → S3 path
- Обновить CRM JS для использования open_file_v3_standalone.php
- Протестировать сохранение файлов
- Удалить тестовые файлы

📊 РЕЗУЛЬТАТ:
- OnlyOffice Standalone РАБОТАЕТ! 
- Файлы открываются напрямую из S3 
- Редактор загружается БЫСТРО 
- Автосохранение настроено  (но нужна доработка callback)
This commit is contained in:
Fedor
2025-11-01 01:02:03 +03:00
parent d7941ac862
commit 269c7ea216
4383 changed files with 282112 additions and 7731 deletions

View File

@@ -0,0 +1,3 @@
S3_ACCESS_KEY=2OMAK5ZNM900TAXM16J7
S3_SECRET_KEY=f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
S3_BUCKET=f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c

View File

@@ -0,0 +1,277 @@
# 🏗️ Архитектура системы мониторинга файлов
## 🎯 Общая схема
```
┌─────────────────────────────────────────────────────────────────────────┐
│ ИСТОЧНИКИ ФАЙЛОВ │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ CRM PHP │ │ Nextcloud │ │ S3 Browser │ │ Внешние │ │
│ │ │ │ WebUI │ │ Cyberduck │ │ скрипты │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └─────┬──────┘ │
│ │ │ │ │ │
│ └─────────────────┼─────────────────┼─────────────────┘ │
│ │ │ │
└───────────────────────────┼─────────────────┼───────────────────────────┘
▼ ▼
┌──────────────────────────────────────┐
│ │
│ TWC S3 Storage (Cloud) │
│ f9825c87-18698658-c378-... │
│ │
└────┬─────────────────────────────┬───┘
│ │
│ (mounted via │ (polling)
│ external │
│ storage) │
▼ ▼
┌──────────────────────┐ ┌──────────────────────────┐
│ Nextcloud │ │ n8n S3 Monitor │
│ Docker Container │ │ Workflow │
│ │ │ │
│ Files change → │ │ Every 30s: │
│ notify_storage_ │ │ 1. List S3 files │
│ update (Redis) │ │ 2. Compare with prev │
└──────────┬───────────┘ │ 3. Detect changes │
│ └─────────┬────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────────────────┐
│ redis_bridge.js │ │ │
│ (Node.js) │ │ (n8n internal) │
│ │ │ │
│ 1. Subscribe NC │ │ │
│ Redis │ │ │
│ 2. Parse events │ │ │
│ 3. Enrich data │ │ │
└──────────┬───────────┘ └─────────┬───────────────┘
│ │
│ │
└────────────┬───────────────┘
┌──────────────────────────────┐
│ CRM Redis │
│ 147.45.146.17:6379 │
│ │
│ Channel: │
│ crm:file:events │
└───────────┬──────────────────┘
│ (subscribe)
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ n8n │ │ CRM PHP │ │ Другие │
│ Workflows │ │ Listeners │ │ сервисы │
└────────────┘ └────────────┘ └────────────┘
```
---
## 📊 Потоки событий
### Поток 1: Файлы через Nextcloud WebUI
```
User uploads file → Nextcloud → S3 Storage →
→ Nextcloud detects change → notify_storage_update (NC Redis) →
→ redis_bridge.js → crm:file:events (CRM Redis) → Обработчики
```
⏱️ **Задержка:** ~1-2 секунды (реал-тайм)
---
### Поток 2: Файлы напрямую в S3
```
External tool → S3 Storage →
→ n8n S3 Monitor (polling every 30s) → Detects change →
→ crm:file:events (CRM Redis) → Обработчики
```
⏱️ **Задержка:** 0-30 секунд (зависит от интервала polling)
---
## 🔄 Компоненты системы
### 1. **redis_bridge.js** (Node.js, работает на хосте)
- **Задача:** Мост между Nextcloud Redis и CRM Redis
- **Вход:** `notify_storage_update` (Nextcloud Redis, port 6380)
- **Выход:** `crm:file:events` (CRM Redis, port 6379)
- **Статус:** ✅ Работает
- **Запуск:**
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
/usr/bin/nodejs redis_bridge.js &
```
### 2. **n8n S3 Monitor Workflow** (в n8n)
- **Задача:** Мониторинг прямых изменений в S3
- **Метод:** Polling (каждые 30 секунд)
- **Вход:** TWC S3 API (ListObjectsV2)
- **Выход:** `crm:file:events` (CRM Redis)
- **Статус:** ⚙️ Нужно настроить
- **Файл:** `n8n_s3_monitor_workflow.json`
### 3. **CRM Redis** (центральная шина событий)
- **Адрес:** `147.45.146.17:6379`
- **Канал:** `crm:file:events`
- **Формат события:**
```json
{
"type": "file_created|file_modified|file_deleted",
"source": "nextcloud|s3_monitor|crm",
"timestamp": "2025-10-30T12:34:56Z",
"path": "full/path/to/file.txt",
"filename": "file.txt",
"size": 12345,
"file_id": 73460,
"etag": "abc123...",
"operation": "create|update|delete"
}
```
---
## 🎯 Сценарии использования
### Сценарий 1: Обработка ERV файлов
```
1. Загружаешь ERV файл в S3 через S3 Browser
2. n8n S3 Monitor обнаруживает файл (через 0-30с)
3. Событие публикуется в Redis → crm:file:events
4. n8n ERV Processor подхватывает событие
5. Скачивает файл из S3
6. Обрабатывает ERV
7. Загружает в CRM
8. Отправляет уведомление
```
### Сценарий 2: Автоматическая обработка PDF счетов
```
1. Клиент загружает PDF в Nextcloud
2. Nextcloud → notify_storage_update → redis_bridge.js
3. Событие в Redis (реал-тайм, ~1с)
4. n8n Invoice Processor:
- Распознаёт текст (OCR)
- Извлекает данные
- Создаёт счёт в CRM
- Уведомляет бухгалтера
```
### Сценарий 3: Синхронизация с внешней системой
```
1. Внешний скрипт пишет в S3
2. n8n S3 Monitor (через 30с)
3. Redis событие
4. n8n External Sync:
- Проверяет формат файла
- Отправляет в external API
- Логирует в CRM
```
---
## ⚙️ Настройки производительности
### Интервал polling S3 Monitor
| Интервал | Задержка | Нагрузка на API | Рекомендация |
|----------|----------|-----------------|--------------|
| 10 сек | 0-10с | Высокая | Только для критичных файлов |
| 30 сек | 0-30с | Средняя | ✅ **Оптимально** |
| 60 сек | 0-60с | Низкая | Для некритичных файлов |
| 300 сек | 0-5мин | Минимальная | Для архивов |
### Количество файлов
- **< 1000 файлов:** Мониторь весь bucket
- **1000-10000:** Используй `Prefix` для фильтрации папок
- **> 10000:** Создай отдельные workflows для разных папок
---
## 🔧 Мониторинг и логи
### Проверка работы redis_bridge.js
```bash
ps aux | grep redis_bridge.js
tail -f /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/redis_bridge.log
```
### Проверка событий в Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
### Проверка n8n workflow
- n8n UI → Workflows → S3 File Monitor → Executions
---
## 🚀 Расширение системы
### Добавление новых источников событий
Любой компонент может публиковать в `crm:file:events`:
**Пример из PHP (CRM):**
```php
$redis = new Redis();
$redis->connect('147.45.146.17', 6379);
$redis->auth('CRM_Redis_Pass_2025_Secure!');
$event = [
'type' => 'file_created',
'source' => 'crm_api',
'timestamp' => date('c'),
'path' => $filePath,
'filename' => basename($filePath),
'size' => filesize($localPath),
'user_id' => $userId
];
$redis->publish('crm:file:events', json_encode($event));
```
**Пример из Python:**
```python
import redis
import json
from datetime import datetime
r = redis.Redis(
host='147.45.146.17',
port=6379,
password='CRM_Redis_Pass_2025_Secure!'
)
event = {
'type': 'file_created',
'source': 'python_script',
'timestamp': datetime.utcnow().isoformat() + 'Z',
'path': file_path,
'filename': os.path.basename(file_path)
}
r.publish('crm:file:events', json.dumps(event))
```
---
## 📝 Итого
✅ **Nextcloud файлы** → реал-тайм через `redis_bridge.js`
✅ **S3 прямые загрузки** → polling через n8n (0-30с задержка)
✅ **CRM файлы** → прямая публикация в Redis
✅ **Единая точка обработки** → Redis канал `crm:file:events`
**Гибкость** → любой сервис может подписаться и обработать
**Всё работает через один канал Redis! 🎉**

View File

@@ -0,0 +1,238 @@
# 🎉 ФИНАЛЬНАЯ СВОДКА - S3 МОНИТОРИНГ
## ✅ ЧТО РАБОТАЕТ:
### 1⃣ **S3 Monitor** (Docker контейнер)
```
Контейнер: s3-monitor
Статус: ✅ Работает
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
Файлов: 24,523
Интервал: каждые 30 секунд
Автоперезапуск: ✅
```
**Что делает:**
- Каждые 30 секунд сканирует S3 bucket
- Получает **ВСЕ** файлы (24,523 штук через pagination)
- Сравнивает с предыдущим состоянием
- Публикует изменения в Redis
**Команды:**
```bash
docker logs s3-monitor -f # Логи в реальном времени
docker stop s3-monitor # Остановить
docker start s3-monitor # Запустить
docker restart s3-monitor # Перезапустить
```
---
### 2⃣ **Redis Bridge** (Nextcloud → CRM Redis)
```
Процесс: /usr/bin/nodejs redis_bridge.js
Статус: ✅ Работает
Порт NC Redis: 127.0.0.1:6380
Порт CRM Redis: 147.45.146.17:6379
```
**Что делает:**
- Слушает Nextcloud Redis канал `notify_storage_update`
- Фильтрует временные файлы (.part, .lock, cache)
- **Дедупликация** - один file_id = одно событие (в течение 5 сек)
- Публикует в CRM Redis канал `crm:file:events`
**Команды:**
```bash
tail -f redis_bridge.log # Логи
ps aux | grep redis_bridge # Статус
pkill -f redis_bridge.js # Остановить
nohup /usr/bin/nodejs redis_bridge.js > redis_bridge.log 2>&1 & # Запустить
```
---
### 3⃣ **Redis Канал** (централизованная шина событий)
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Channel: crm:file:events
```
---
## 📊 ФОРМАТ СОБЫТИЙ:
### От S3 Monitor:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "folder/subfolder/file.xlsx",
"filename": "file.xlsx",
"action": "created",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z"
}
```
### От Nextcloud (redis_bridge):
```json
{
"type": "file_update",
"source": "nextcloud",
"timestamp": "2025-10-30T20:52:21.236Z",
"storage_id": 4,
"path": "crm2/CRM_Active_Files/file.pdf",
"file_id": 42594,
"filename": "file.pdf",
"operation": "update"
}
```
**Оба публикуются в один канал:** `crm:file:events`
---
## 🎯 КАК ОБРАБАТЫВАТЬ В N8N:
### Шаг 1: Импортируй workflow обработчик
Файл: `n8n_s3_event_processor.json`
### Шаг 2: Настрой Redis Trigger
```
Node: Redis Subscribe
Channel: crm:file:events
Credential: CRM Redis
```
### Шаг 3: Parse JSON (если нужно)
```javascript
// n8n автоматически парсит, но если нужно:
const message = $json.message;
const event = typeof message === 'string' ? JSON.parse(message) : message;
return [{ json: event }];
```
### Шаг 4: Фильтруй по типу
```javascript
// Только новые файлы
$json.type === 'file_created'
// Только XLSX
$json.filename.endsWith('.xlsx')
// Только из определённой папки
$json.path.includes('Documents/')
```
### Шаг 5: Обработай файл
```
Switch по расширению:
├─ .xlsx → Обработка Excel
├─ .pdf → OCR и извлечение данных
├─ .jpg → Обработка изображений
└─ Другие → Логирование
```
---
## 🧪 ПРОВЕРКА СОБЫТИЙ:
### Подпишись на Redis:
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
### Загрузи файл:
- Через Nextcloud WebUI
- Через S3 Browser
- Через aws-cli
### Увидишь событие:
```
1) "message"
2) "crm:file:events"
3) "{\"type\":\"file_created\",\"filename\":\"test.pdf\",...}"
```
---
## 📋 ИСТОЧНИКИ СОБЫТИЙ:
| Источник | Метод | Задержка | Фильтры |
|----------|-------|----------|---------|
| **Nextcloud WebUI** | Redis Bridge | 1-2 сек | ✅ Дедупликация<br>✅ Фильтр .part<br>✅ Фильтр cache |
| **S3 прямая загрузка** | S3 Monitor | 0-30 сек | Нет |
| **CRM API** | Прямая публикация | 0 сек | Настраивается |
---
## 🔧 ДОПОЛНИТЕЛЬНАЯ ФИЛЬТРАЦИЯ В N8N:
Если всё ещё приходит много событий от Nextcloud, добавь в n8n:
```javascript
// Фильтр: пропускаем дубликаты по filename + timestamp
const cache = $getWorkflowStaticData('node');
cache.recent = cache.recent || [];
const key = `${$json.filename}_${$json.file_id}`;
const now = Date.now();
// Очищаем старые (>10 секунд)
cache.recent = cache.recent.filter(item => (now - item.time) < 10000);
// Проверяем дубликат
if (cache.recent.find(item => item.key === key)) {
return []; // Пропускаем дубликат
}
// Добавляем в кеш
cache.recent.push({ key, time: now });
return [$input.item];
```
---
## 📁 ФАЙЛЫ:
Все в:
```
/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/
```
**Рабочие скрипты:**
-`s3_monitor_docker.js` - S3 мониторинг (запущен в Docker)
-`redis_bridge.js` - Nextcloud→CRM мост (запущен)
-`.env.s3monitor` - credentials для S3
**N8N Workflows для импорта:**
- `n8n_s3_event_processor.json` - обработчик событий (НОВЫЙ!)
- `n8n_nextcloud_activity_monitor.json` - альтернатива через Activity API
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor (если не хочешь Docker)
**Документация:**
- `SETUP_CHECKLIST.md` - чек-лист настройки
- `S3_MONITORING_GUIDE.md` - руководство по S3
- `ARCHITECTURE.md` - схема архитектуры
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
---
## 🎉 ГОТОВО!
**Система полностью работает:**
- ✅ S3 мониторинг (24,523 файла)
- ✅ Nextcloud мониторинг (с дедупликацией)
- ✅ Redis публикация
- ✅ Автоперезапуск
- ✅ Фильтрация дубликатов
**Теперь импортируй `n8n_s3_event_processor.json` в n8n и начинай обрабатывать файлы!** 🚀

View File

@@ -0,0 +1,377 @@
# 🌐 Nextcloud API - Обзор и возможности
## 📋 Доступные API
### 1. **WebDAV API** ✅ (РАБОТАЕТ)
**Базовый URL:** `https://office.clientright.ru:8443/remote.php/webdav/`
**Аутентификация:** Basic Auth (admin + app password)
**Возможности:**
- ✅ Список файлов и папок (PROPFIND)
- ✅ Загрузка файлов (PUT)
- ✅ Скачивание файлов (GET)
- ✅ Удаление файлов (DELETE)
- ✅ Создание папок (MKCOL)
- ✅ Перемещение/копирование (MOVE/COPY)
- ✅ Получение метаданных (PROPFIND)
**Пример - список файлов:**
```bash
curl -u "admin:APP_PASSWORD" \
-X PROPFIND \
"https://office.clientright.ru:8443/remote.php/webdav/" \
-H "Depth: 1"
```
**Пример - загрузка файла:**
```bash
curl -u "admin:APP_PASSWORD" \
-T /path/to/local/file.txt \
"https://office.clientright.ru:8443/remote.php/webdav/file.txt"
```
**Пример - скачивание файла:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/remote.php/webdav/file.txt" \
-o downloaded.txt
```
---
### 2. **OCS API (Open Collaboration Services)** ✅
**Базовый URL:** `https://office.clientright.ru:8443/ocs/v2.php/`
**Заголовки:** `OCS-APIRequest: true`
**Формат ответа:** JSON (`?format=json`)
#### 2.1 **Capabilities API** (информация о сервере)
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/capabilities?format=json" \
-H "OCS-APIRequest: true"
```
**Ответ включает:**
- Версию Nextcloud (31.0.9)
- Доступные возможности
- Лимиты загрузки
- Настройки шаринга
---
#### 2.2 **Activity API** ✅ (СОБЫТИЯ ФАЙЛОВ!)
**URL:** `https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity`
**Параметры:**
- `format=json` - формат ответа
- `limit=N` - количество событий
- `since=TIMESTAMP` - события после определённой даты
**Пример:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10" \
-H "OCS-APIRequest: true"
```
**Типы событий:**
- `file_created` - файл создан
- `file_changed` - файл изменён
- `file_deleted` - файл удалён
- `file_restored` - файл восстановлен
- `file_shared` - файл расшарен
**Структура события:**
```json
{
"activity_id": 195,
"type": "file_created",
"subject": "Вы создали «experimental_report.xlsx»",
"message": "",
"object_type": "files",
"object_id": 73460,
"object_name": "/experimental_report.xlsx",
"datetime": "2025-10-30T12:53:40+00:00",
"user": "admin"
}
```
**⚠️ Ограничения:**
- Нет real-time уведомлений (только polling)
- События агрегируются (несколько файлов в одном событии)
- Может быть задержка до минуты
---
#### 2.3 **Users API**
**Список пользователей:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users?format=json" \
-H "OCS-APIRequest: true"
```
**Информация о пользователе:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v1.php/cloud/users/admin?format=json" \
-H "OCS-APIRequest: true"
```
---
#### 2.4 **Sharing API**
**Список расшаренных файлов:**
```bash
curl -u "admin:APP_PASSWORD" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
-H "OCS-APIRequest: true"
```
**Создать публичную ссылку:**
```bash
curl -u "admin:APP_PASSWORD" \
-X POST \
-d "path=/file.txt&shareType=3" \
"https://office.clientright.ru:8443/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json" \
-H "OCS-APIRequest: true"
```
---
### 3. **Direct Download URL**
Для файлов можно получить прямую ссылку скачивания:
**Формат:**
```
https://office.clientright.ru:8443/index.php/apps/files/ajax/download.php?dir=/&files=filename.txt
```
Или через WebDAV:
```
https://office.clientright.ru:8443/remote.php/webdav/filename.txt
```
---
## 🎯 Использование для мониторинга файлов
### Вариант 1: Activity API Polling (РЕКОМЕНДУЮ для Nextcloud)
**Создай n8n workflow:**
```
┌─────────────────────────────────────────────┐
│ Schedule (каждые 30 сек) │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ HTTP Request │
│ GET /ocs/v2.php/apps/activity/api/v2/ │
│ activity?format=json&limit=100 │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ Code (JS) │
│ - Фильтруем file_created/changed/deleted │
│ - Сохраняем последний activity_id │
│ - Возвращаем только новые события │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│ Redis Publish │
│ Channel: crm:file:events │
└─────────────────────────────────────────────┘
```
**Преимущества:**
- ✅ Официальный API
- ✅ Надёжный
- ✅ Детальная информация о событиях
-Не требует доступа к Redis Nextcloud
**Недостатки:**
- ⚠️ Задержка 30-60 сек (polling)
- ⚠️ События агрегируются
---
### Вариант 2: Redis Bridge (УЖЕ РАБОТАЕТ!)
```
Nextcloud Redis (notify_storage_update) →
→ redis_bridge.js →
→ CRM Redis (crm:file:events)
```
**Преимущества:**
- ✅ Real-time (~1-2 сек)
-Не нагружает Nextcloud API
**Недостатки:**
- ⚠️ Требует доступ к внутреннему Redis
- ⚠️ Меньше метаданных
---
## 📊 Сравнение подходов
| Метод | Задержка | Детали | Сложность | Надёжность |
|-------|----------|--------|-----------|------------|
| **Activity API** | 30-60с | ⭐⭐⭐ | Низкая | ⭐⭐⭐ |
| **Redis Bridge** | 1-2с | ⭐⭐ | Средняя | ⭐⭐⭐ |
| **S3 Monitor** | 0-30с | ⭐⭐ | Низкая | ⭐⭐⭐ |
| **WebDAV Poll** | 60с+ | ⭐ | Низкая | ⭐⭐ |
---
## 🛠️ Примеры кода
### PHP - Получение последних событий
```php
<?php
$username = 'admin';
$password = 'APP_PASSWORD';
$url = 'https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=10';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['OCS-APIRequest: true']);
$response = curl_exec($ch);
$data = json_decode($response, true);
foreach ($data['ocs']['data'] as $activity) {
if (in_array($activity['type'], ['file_created', 'file_changed', 'file_deleted'])) {
echo "Event: {$activity['type']}\n";
echo "File: {$activity['object_name']}\n";
echo "Time: {$activity['datetime']}\n";
echo "---\n";
}
}
?>
```
### Node.js - Activity API Monitor
```javascript
const axios = require('axios');
const Redis = require('ioredis');
const CONFIG = {
nextcloud: {
url: 'https://office.clientright.ru:8443',
username: 'admin',
password: 'APP_PASSWORD'
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
pollInterval: 30000 // 30 секунд
};
const redis = new Redis(CONFIG.redis);
let lastActivityId = 0;
async function checkActivities() {
try {
const response = await axios.get(
`${CONFIG.nextcloud.url}/ocs/v2.php/apps/activity/api/v2/activity`,
{
params: { format: 'json', limit: 100 },
headers: { 'OCS-APIRequest': 'true' },
auth: {
username: CONFIG.nextcloud.username,
password: CONFIG.nextcloud.password
}
}
);
const activities = response.data.ocs.data;
const fileEvents = activities.filter(a =>
['file_created', 'file_changed', 'file_deleted'].includes(a.type) &&
a.activity_id > lastActivityId
);
for (const event of fileEvents.reverse()) {
const payload = {
type: event.type,
source: 'nextcloud_activity',
timestamp: event.datetime,
file_id: event.object_id,
path: event.object_name,
filename: event.object_name.split('/').pop(),
user: event.user
};
await redis.publish('crm:file:events', JSON.stringify(payload));
console.log(`📤 Published: ${event.type} - ${event.object_name}`);
lastActivityId = Math.max(lastActivityId, event.activity_id);
}
} catch (error) {
console.error('❌ Error:', error.message);
}
}
// Запуск
console.log('🚀 Nextcloud Activity Monitor');
setInterval(checkActivities, CONFIG.pollInterval);
checkActivities();
```
---
## 🎯 Рекомендации
### Для твоего use case:
**Комбинируй несколько подходов:**
1. **Nextcloud файлы (WebUI)****Redis Bridge** (real-time, 1-2с)
2. **S3 прямые загрузки****n8n S3 Monitor** (polling, 0-30с)
3. **CRM загрузки****Прямая публикация в Redis** (instant)
**Все события в одном канале:** `crm:file:events`
**Альтернатива (если нужна простота):**
- Используй **только Activity API** через n8n для Nextcloud событий
- Плюс **S3 Monitor** для прямых загрузок в S3
---
## 📚 Полезные ссылки
- [Nextcloud WebDAV Documentation](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/)
- [Nextcloud OCS API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/)
- [Activity API](https://github.com/nextcloud/activity/blob/master/docs/endpoint-v2.md)
---
## 🔐 Безопасность
**App Password:** `tGHKS-3cC9m-7Hggb-65Awk-zxWQE`
**Пользователь:** `admin`
⚠️ **Важно:** Используй App Passwords, а не основной пароль!
---
**Готово! Теперь ты знаешь все доступные API Nextcloud! 🎉**

View File

@@ -0,0 +1,169 @@
# 🔑 Nextcloud Redis - Креды и подключение
## 📋 Основная информация
**Контейнер:** `nextcloud-redis`
**IP внутри Docker сети:** `172.24.0.4`
**Порт:** `6379`
**Пароль:** `НЕТ` (не установлен)
---
## 🔌 Варианты подключения
### **ВАРИАНТ 1: Из хоста (если проброшен порт)**
**Если пробросить порт наружу:**
```bash
# Перезапустить контейнер с проброшенным портом:
docker stop nextcloud-redis
docker start -p 6378:6379 nextcloud-redis
```
**Тогда подключаться так:**
```
Host: localhost (или 147.45.146.17)
Port: 6378
Password: (пусто)
```
---
### **ВАРИАНТ 2: Через Docker network IP**
**Из другого контейнера в той же сети:**
```
Host: 172.24.0.4
Port: 6379
Password: (пусто)
```
---
### **ВАРИАНТ 3: Из самого хоста (если в той же сети)**
**Если хост в той же Docker сети:**
```
Host: 172.24.0.4
Port: 6379
Password: (пусто)
```
---
## 📡 Каналы Redis для подписки
### **Главный канал для файловых изменений:**
```
notify_storage_update
```
Этот канал публикует события когда:
- Файл создан/удалён/переименован
- Папка создана/удалена/переименована
### **Другие полезные каналы:**
```
notify_activity # Общая активность
notify_notification # Уведомления пользователей
notify_pre_auth # Пред-аутентификация
```
---
## 🧪 Тест подключения
### **Из командной строки:**
```bash
# Подключиться к Redis через docker exec:
docker exec -it nextcloud-redis redis-cli
# Или если порт проброшен:
redis-cli -h localhost -p 6378
```
**Тест подписки на канал:**
```redis
SUBSCRIBE notify_storage_update
```
---
## 📝 Формат сообщений
Сообщения в канале `notify_storage_update` имеют формат:
```json
{
"type": "notify_storage_update",
"path": "/admin/files/Documents/Projects/Проект_390983/файл_395695.docx",
"user": "admin",
"action": "write" | "delete" | "rename",
"oldPath": "...", // только для rename
"timestamp": "..."
}
```
---
## 🔧 Для n8n подключения
**Настройки в n8n:**
```
Host: 172.24.0.4 (или localhost:6378 если проброшен порт)
Port: 6379 (или 6378 если проброшен)
Password: (оставить пустым)
Database: 0
```
**Триггер:**
- Использовать "Redis Trigger" ноду
- Channel: `notify_storage_update`
---
## 🚀 Для нашего Node.js listener
**Обновить `nextcloud_listener.js`:**
```javascript
const redis = new Redis({
host: '172.24.0.4', // или localhost если проброшен порт
port: 6379, // или 6378 если проброшен
password: '' // пусто
});
redis.subscribe('notify_storage_update');
redis.on('message', (channel, message) => {
const event = JSON.parse(message);
// Обработка события
});
```
---
## ⚠️ ВАЖНО
1. **Безопасность:** Redis БЕЗ пароля доступен только из Docker сети!
2. **Если нужен доступ снаружи:** Обязательно установи пароль!
3. **Мониторинг:** Следи за нагрузкой на Redis при подписке на каналы
---
## 🔐 Рекомендация: Установить пароль
Если планируешь пробрасывать порт наружу:
```bash
docker exec nextcloud-redis redis-cli CONFIG SET requirepass аш_пароль"
```
И добавить в Nextcloud config.php:
```php
'redis' => array (
'atype' => 'redis',
'host' => 'nextcloud-redis',
'port' => 6379,
'password' => аш_пароль',
),
```

View File

@@ -0,0 +1,182 @@
# 🎉 PRODUCTION READY - Мониторинг файлов
## ✅ ЧТО РАБОТАЕТ:
### 1⃣ Nextcloud Activity Monitor
**Скрипт:** `nextcloud_activity_monitor.js`
**Запущен:** ✅ (PID: 2122)
**Лог:** `nextcloud_activity.log`
**Мониторит:**
- Файлы загруженные через Nextcloud WebUI
- Файлы созданные/изменённые в Nextcloud
**Метод:**
- Nextcloud Activity API (polling каждые 30 сек)
- Разбивает агрегированные события на отдельные файлы
- БЕЗ дубликатов!
**Формат события:**
```json
{
"type": "file_created",
"source": "nextcloud_activity",
"timestamp": "2025-10-30T12:53:40+00:00",
"file_id": 73460,
"path": "/experimental_report.xlsx",
"filename": "experimental_report.xlsx",
"user": "admin",
"action": "created"
}
```
**Команды:**
```bash
# Статус
ps aux | grep nextcloud_activity_monitor
# Логи
tail -f nextcloud_activity.log
# Остановить
pkill -f nextcloud_activity_monitor.js
# Запустить
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
```
---
### 2⃣ S3 Monitor (Docker)
**Контейнер:** `s3-monitor`
**Запущен:** ✅ (Up 40 минут)
**Скрипт:** `s3_monitor_docker.js`
**Мониторит:**
- Файлы загруженные напрямую в S3
- Через S3 Browser, aws-cli, Cyberduck, скрипты
- Любые изменения в bucket
**Метод:**
- S3 ListObjectsV2 API (polling каждые 30 сек)
- Pagination - получает ВСЕ файлы (24,522 файла!)
- Сравнение по ETag
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
**Формат события:**
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
"filename": "file.xlsx",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z",
"action": "created"
}
```
**Команды:**
```bash
# Статус
docker ps | grep s3-monitor
# Логи
docker logs s3-monitor -f
# Остановить
docker stop s3-monitor
# Запустить
docker start s3-monitor
# Перезапустить
docker restart s3-monitor
```
---
### 3⃣ Redis Канал (центральная шина)
**Host:** `147.45.146.17`
**Port:** `6379`
**Password:** `CRM_Redis_Pass_2025_Secure!`
**Channel:** `crm:file:events`
**Подписаться:**
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
---
## 🚫 ЧТО ОСТАНОВЛЕНО:
### ❌ redis_bridge.js
**Причина:** Давал неполные данные, много дубликатов
**Заменён на:** Nextcloud Activity Monitor (даёт чистые данные)
---
## 📊 СРАВНЕНИЕ ДАННЫХ:
| Поле | Nextcloud Activity | S3 Monitor |
|------|-------------------|------------|
| **type** | ✅ file_created/changed/deleted | ✅ file_created/modified/deleted |
| **source** | nextcloud_activity | s3_monitor |
| **filename** | ✅ | ✅ |
| **path** | ✅ (Nextcloud путь) | ✅ (S3 полный путь) |
| **file_id** | ✅ | ❌ |
| **user** | ✅ | ❌ |
| **size** | ❌ | ✅ |
| **etag** | ❌ | ✅ |
| **mime_type** | ❌ | ❌ |
**Дополняют друг друга!** 🎯
---
## 🔧 АВТОЗАПУСК ПРИ ПЕРЕЗАГРУЗКЕ СЕРВЕРА:
### S3 Monitor:
✅ Уже настроен (`--restart unless-stopped`)
### Nextcloud Activity Monitor:
Создам systemd service:
```bash
sudo tee /etc/systemd/system/nextcloud-activity-monitor.service << 'EOF'
[Unit]
Description=Nextcloud Activity Monitor
After=network.target redis.service
[Service]
Type=simple
User=root
WorkingDirectory=/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
ExecStart=/usr/bin/nodejs nextcloud_activity_monitor.js
Restart=always
RestartSec=10
StandardOutput=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
StandardError=append:/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/nextcloud_activity.log
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable nextcloud-activity-monitor
sudo systemctl start nextcloud-activity-monitor
```
---
## 🎯 ГОТОВО!
**Система полностью работает в production режиме!** 🚀
Хочешь чтобы я создал systemd service для автозапуска Nextcloud Activity Monitor? 😊

View File

@@ -0,0 +1,104 @@
# ⚡ Quick Start - Мониторинг файлов
## 🎯 Быстрая проверка системы
```bash
bash START.sh
```
Покажет статус всех компонентов и запустит остановленные.
---
## 📊 Что работает прямо сейчас:
### ✅ Nextcloud Activity Monitor
- **PID:** 2122
- **Лог:** `nextcloud_activity.log`
- **Что делает:** Ловит файлы из Nextcloud WebUI
- **Задержка:** 30 сек
### ✅ S3 Monitor (Docker)
- **Контейнер:** `s3-monitor`
- **Uptime:** 40+ минут
- **Что делает:** Ловит файлы загруженные напрямую в S3
- **Задержка:** 30 сек
- **Файлов:** 24,522
### ✅ Redis канал
- **Адрес:** `147.45.146.17:6379`
- **Канал:** `crm:file:events`
- **Статус:** Оба монитора публикуют события ✅
---
## 🧪 Быстрый тест
### Тест 1: Загрузи файл в Nextcloud
```bash
# В другом терминале подпишись на события
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
Загрузи файл через Nextcloud WebUI → через 30 сек увидишь событие!
### Тест 2: Загрузи файл в S3
```bash
echo "test" > /tmp/test.txt
aws s3 cp /tmp/test.txt \
s3://f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/test_$(date +%s).txt \
--endpoint-url https://s3.twcstorage.ru
```
Через 0-30 сек увидишь событие!
---
## 🔧 Команды управления
```bash
# Проверка статуса
bash START.sh
# Логи в реальном времени
tail -f nextcloud_activity.log
docker logs s3-monitor -f
# Остановка
pkill -f nextcloud_activity_monitor.js
docker stop s3-monitor
# Запуск
bash START.sh
```
---
## 📚 Документация
- `README.md` - обзор системы
- `PRODUCTION_READY.md` - production конфигурация
- `ARCHITECTURE.md` - архитектура
---
## 🆘 Troubleshooting
**Нет событий?**
1. Проверь статус: `bash START.sh`
2. Проверь логи: `tail -f nextcloud_activity.log`
3. Проверь Redis: подпишись на канал
**Много дубликатов?**
- От Nextcloud: дедупликация включена (1 событие вместо 6)
- От S3: дубликатов нет
**Нужна помощь?**
- Читай `PRODUCTION_READY.md`
- Проверяй логи
---
**Всё готово! 🚀**

View File

@@ -0,0 +1,137 @@
# 🔔 Система мониторинга файлов CRM
Автоматический мониторинг изменений файлов в S3 и Nextcloud с публикацией событий в Redis.
## 🎯 Компоненты системы
### 1. Nextcloud Activity Monitor
**Файл:** `nextcloud_activity_monitor.js`
**Назначение:** Мониторинг файлов загруженных через Nextcloud WebUI
**Метод:** Nextcloud Activity API
**Интервал:** 30 секунд
**Запуск:**
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
```
**Управление:**
```bash
ps aux | grep nextcloud_activity_monitor # Статус
tail -f nextcloud_activity.log # Логи
pkill -f nextcloud_activity_monitor.js # Остановить
```
---
### 2. S3 Monitor (Docker)
**Контейнер:** `s3-monitor`
**Назначение:** Мониторинг файлов загруженных напрямую в S3
**Bucket:** `f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c`
**Интервал:** 30 секунд
**Файлов:** ~24,500
**Управление:**
```bash
docker ps | grep s3-monitor # Статус
docker logs s3-monitor -f # Логи
docker stop s3-monitor # Остановить
docker start s3-monitor # Запустить
docker restart s3-monitor # Перезапустить
```
---
### 3. Redis (центральная шина событий)
**Адрес:** `147.45.146.17:6379`
**Канал:** `crm:file:events`
**Password:** `CRM_Redis_Pass_2025_Secure!`
**Подписка:**
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
---
## 📊 Формат событий
### От Nextcloud Activity Monitor:
```json
{
"type": "file_created",
"source": "nextcloud_activity",
"timestamp": "2025-10-30T12:53:40+00:00",
"file_id": 73460,
"path": "/experimental_report.xlsx",
"filename": "experimental_report.xlsx",
"user": "admin",
"action": "created"
}
```
### От S3 Monitor:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T20:49:31.593Z",
"path": "crm2/CRM_Active_Files/Documents/file.xlsx",
"filename": "file.xlsx",
"size": 8224,
"etag": "7004954627252c9d0a7e6417f8325d07",
"last_modified": "2025-10-30T20:49:14.132Z",
"action": "created"
}
```
---
## 🔧 Credentials
### Nextcloud API:
```
URL: https://office.clientright.ru:8443
User: admin
App Password: tGHKS-3cC9m-7Hggb-65Awk-zxWQE
```
### S3 (TWC Storage):
```
Endpoint: https://s3.twcstorage.ru
Region: ru-1
Access Key: 2OMAK5ZNM900TAXM16J7
Secret Key: f4ADllb5VZBAt2HdsyB8WcwVEU7U74MwFCa1DARG
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
```
---
## 📚 Дополнительные документы
- `PRODUCTION_READY.md` - полное описание production конфигурации
- `ARCHITECTURE.md` - схема архитектуры системы
- `S3_MONITORING_GUIDE.md` - руководство по S3 мониторингу
- `NEXTCLOUD_API_OVERVIEW.md` - обзор Nextcloud API
- `SETUP_CHECKLIST.md` - чек-лист настройки
---
## 🚀 Для разработчиков
### n8n Workflows (готовые для импорта):
- `n8n_s3_event_processor.json` - обработчик событий из Redis
- `n8n_nextcloud_activity_monitor.json` - альтернатива через n8n
- `n8n_s3_monitor_workflow.json` - альтернатива S3 Monitor через n8n
### Утилиты:
- `get_s3_credentials.sh` - получение S3 credentials
---
**Дата создания:** 30 октября 2025
**Версия:** 1.0
**Статус:** Production Ready ✅

View File

@@ -0,0 +1,248 @@
# 🔍 Руководство по мониторингу S3
## Проблема
Тебе нужно ловить **любые** изменения файлов в S3 bucket, даже если они загружены:
- Вручную через S3 Browser / Cyberduck
- Из внешних скриптов
- Не через CRM или Nextcloud
## ❌ Почему не Event Notifications?
TWC Storage **не поддерживает** S3 Event Notifications официально (не документировано).
## ✅ РЕШЕНИЕ: n8n Workflow с Polling
### Как работает:
```
n8n каждые 30 сек → Список файлов в S3 → Сравнение с предыдущим состоянием →
→ Обнаружены изменения → Публикация в Redis → Твои обработчики
```
---
## 📋 Пошаговая инструкция
### Шаг 1: Импортируй workflow в n8n
1. Открой n8n: https://n8n.clientright.pro
2. Создай новый workflow
3. Нажми **Import from File**
4. Загрузи файл: `n8n_s3_monitor_workflow.json`
### Шаг 2: Настрой S3 Credentials
В n8n создай credentials:
**Тип:** AWS S3
**Имя:** `TWC S3`
**Параметры:**
```
Access Key ID: [твой S3 ключ из Nextcloud]
Secret Access Key: [твой S3 секрет из Nextcloud]
Region: ru-1
Custom Endpoints: ✅ (включить!)
S3 Endpoint: https://s3.twcstorage.ru
Force Path Style: ✅ (включить!)
```
**Как получить ключи:**
```bash
docker exec nextcloud-fresh php occ files_external:list --output=json | jq -r '.[0].configuration | "Key: \(.key)\nSecret: \(.secret)\nBucket: \(.bucket)"'
```
### Шаг 3: Настрой Redis Credentials
**Тип:** Redis
**Имя:** `CRM Redis`
**Параметры:**
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Database: 0
```
### Шаг 4: Настрой Environment Variables (если нужно)
В n8n Settings → Environment Variables:
```
S3_BUCKET=f9825c87-18698658-c378-4aa7-91cc-0c131bebccda
WEBHOOK_URL=https://твой-эндпоинт.com/webhook (опционально)
```
### Шаг 5: Настрой Bucket и Prefix
В ноде **List S3 Files**:
- `Bucket Name`: укажи свой bucket (или используй `{{$env.S3_BUCKET}}`)
- `Prefix`: укажи папку для мониторинга (например `nextcloud/data/admin/files/`)
- Оставь пустым для мониторинга всего bucket
### Шаг 6: Активируй Workflow
1. Нажми **Active** (включи workflow)
2. Первый запуск создаст начальное состояние файлов
3. Последующие запуски будут сравнивать с предыдущим состоянием
---
## 🧪 Тестирование
### 1. Загрузи тестовый файл в S3
Через S3 Browser, Cyberduck или aws-cli:
```bash
echo "test" > test.txt
aws s3 cp test.txt s3://твой-bucket/test.txt \
--endpoint-url https://s3.twcstorage.ru
```
### 2. Подожди 30 секунд (интервал polling)
### 3. Проверь Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
SUBSCRIBE crm:file:events
```
Должно прийти:
```json
{
"type": "file_created",
"source": "s3_monitor",
"timestamp": "2025-10-30T12:34:56Z",
"path": "test.txt",
"filename": "test.txt",
"size": 5,
"etag": "\"098f6bcd4621d373cade4e832627b4f6\"",
"last_modified": "2025-10-30T12:34:50Z"
}
```
---
## ⚙️ Настройка интервала
Измени интервал проверки в ноде **"Каждые 30 секунд"**:
- **10 секунд** - почти реал-тайм, но больше нагрузка на S3 API
- **30 секунд** - оптимальный баланс (рекомендуется)
- **60 секунд** - экономия API запросов
**Важно:** TWC может лимитировать количество API запросов!
---
## 📊 Типы событий
Workflow генерирует 3 типа событий:
1. **`file_created`** - новый файл появился в bucket
2. **`file_modified`** - файл изменился (другой ETag)
3. **`file_deleted`** - файл удалён из bucket
---
## 🔄 Обработка событий в других workflows
Создай новый workflow в n8n:
### Trigger: Redis (Subscribe)
```
Host: 147.45.146.17
Port: 6379
Password: CRM_Redis_Pass_2025_Secure!
Channel: crm:file:events
```
### Filter: По типу события
```javascript
// Обрабатываем только создание файлов
return $json.type === 'file_created';
```
### Switch: По расширению файла
```javascript
const ext = $json.filename.split('.').pop().toLowerCase();
switch(ext) {
case 'pdf':
return [0]; // Обработка PDF
case 'jpg':
case 'png':
return [1]; // Обработка изображений
case 'xlsx':
case 'csv':
return [2]; // Обработка таблиц
default:
return [3]; // Остальные файлы
}
```
---
## 🎯 Пример: Автоматическая обработка ERV файлов
```
Redis Subscribe (crm:file:events) →
→ Filter (filename contains "erv") →
→ Download from S3 →
→ Process ERV →
→ Upload to CRM →
→ Notify user
```
---
## 📝 Мониторинг нескольких buckets
Если тебе нужно мониторить несколько buckets:
1. **Вариант 1:** Создай отдельный workflow для каждого bucket
2. **Вариант 2:** Используй Loop в workflow для перебора buckets
---
## 🚨 Важные замечания
1. **State сохраняется в Static Data** - не удаляй workflow без экспорта!
2. **Первый запуск не генерирует события** - только создаёт начальное состояние
3. **ETag используется для определения изменений** - если файл перезаписан с тем же содержимым, событие не сработает
4. **Polling = задержка** - событие придёт через 0-30 секунд после реального изменения
---
## 🔧 Troubleshooting
### Проблема: Не приходят события
- Проверь что workflow **Active** (зелёная галочка)
- Проверь логи workflow (Execute → View executions)
- Проверь credentials (S3 и Redis)
### Проблема: Слишком много событий
- Уменьши область мониторинга через `Prefix`
- Увеличь интервал polling до 60-120 секунд
### Проблема: Пропускаются изменения
- Уменьши интервал до 10-15 секунд
- Проверь что State сохраняется (Static Data)
---
## 📚 Дополнительные материалы
- [n8n AWS S3 Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awss3/)
- [n8n Redis Node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.redis/)
- [n8n Code Node](https://docs.n8n.io/code-examples/methods-variables-reference/)
---
## 🎉 Готово!
Теперь у тебя есть полноценный мониторинг S3 bucket в реальном времени!
Все изменения файлов будут автоматически публиковаться в Redis канал `crm:file:events`,
откуда их могут подхватить другие твои системы (CRM, другие n8n workflows, и т.д.)

View File

@@ -0,0 +1,228 @@
# ✅ Чек-лист настройки S3 мониторинга
## 📋 Что нужно сделать
### Шаг 1: Получи S3 Credentials ✅
```bash
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
bash get_s3_credentials.sh
```
**Сохрани куда-нибудь:**
- Access Key ID
- Secret Access Key
- Bucket name
- Endpoint: `https://s3.twcstorage.ru`
- Region: `ru-1`
---
### Шаг 2: Импортируй workflow в n8n ⏳
1. Открой https://n8n.clientright.pro
2. Нажми **"+"** → **Import from File**
3. Выбери файл: `/var/www/.../n8n_s3_monitor_workflow.json`
4. Нажми **Import**
---
### Шаг 3: Настрой S3 Credentials в n8n ⏳
1. В n8n иди в **Settings** (⚙️) → **Credentials**
2. Нажми **Add Credential** → выбери **AWS**
3. Заполни:
- **Name:** `TWC S3`
- **Access Key ID:** (из шага 1)
- **Secret Access Key:** (из шага 1)
- **Region:** `ru-1`
4. **Включи** `Custom Endpoints`
5. **S3 Endpoint:** `https://s3.twcstorage.ru`
6. **Включи** `Force Path Style`
7. Нажми **Test** → должно быть ✅
8. **Save**
---
### Шаг 4: Настрой Redis Credentials в n8n ⏳
1. **Add Credential****Redis**
2. Заполни:
- **Name:** `CRM Redis`
- **Host:** `147.45.146.17`
- **Port:** `6379`
- **Password:** `CRM_Redis_Pass_2025_Secure!`
- **Database:** `0`
3. **Test** → ✅
4. **Save**
---
### Шаг 5: Настрой workflow ⏳
1. Открой импортированный workflow **"S3 File Monitor"**
2. Кликни на ноду **"List S3 Files"**
3. В поле **Credential for AWS** выбери `TWC S3`
4. В поле **Bucket Name:**
- Вариант 1: Впиши имя bucket из шага 1
- Вариант 2: Оставь `{{$env.S3_BUCKET}}` и настрой env variable
5. В поле **Prefix** (опционально):
- Оставь пустым для мониторинга всего bucket
- Или укажи папку, например: `nextcloud/data/admin/files/`
6. Кликни на ноду **"Publish to Redis"**
7. Выбери credential: `CRM Redis`
8. **Save** workflow
---
### Шаг 6: Активируй workflow ⏳
1. Переключи тумблер **Active** в ON (вверху справа)
2. Workflow начнёт работать!
**Первый запуск:**
- Создаст начальное состояние файлов
- **НЕ** сгенерирует события (это нормально!)
**Последующие запуски (каждые 30 сек):**
- Будут сравнивать с предыдущим состоянием
- Генерировать события при изменениях
---
### Шаг 7: Протестируй! 🧪
#### Тест 1: Загрузи файл в S3
Через **S3 Browser** или **aws-cli**:
```bash
echo "test content" > /tmp/test-file.txt
aws s3 cp /tmp/test-file.txt s3://ИМЯ-BUCKET/test-file.txt \
--endpoint-url https://s3.twcstorage.ru
```
#### Тест 2: Подожди 30 секунд
⏱️ Время для следующего polling цикла...
#### Тест 3: Проверь Redis
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' \
--csv SUBSCRIBE crm:file:events
```
Должно прийти:
```
"subscribe","crm:file:events",1
"message","crm:file:events","{\"type\":\"file_created\",\"source\":\"s3_monitor\",...}"
```
#### Тест 4: Проверь n8n executions
1. В n8n → **S3 File Monitor** workflow
2. Нажми **Executions** (внизу)
3. Посмотри последние запуски
4. Должны быть ✅ зелёные
---
### Шаг 8: Настрой обработчик событий (опционально) ⏳
Создай новый workflow в n8n для обработки событий:
1. **Trigger:** Redis (Subscribe)
- Channel: `crm:file:events`
- Credential: `CRM Redis`
2. **Filter** по типу файла:
```javascript
// Обрабатываем только PDF
return $json.filename.endsWith('.pdf');
```
3. **Твоя логика:**
- Download from S3
- Process
- Upload to CRM
- Notify user
---
## 🔧 Troubleshooting
### ❌ Workflow не запускается
- Проверь что он **Active** (зелёная галочка)
- Проверь Executions → есть ли ошибки?
### ❌ S3 Connection failed
- Проверь credentials (Access Key, Secret)
- Проверь что включен `Force Path Style` ✅
- Проверь endpoint: `https://s3.twcstorage.ru`
### ❌ Redis Connection failed
- Проверь firewall: порт 6379 открыт?
- Проверь пароль: `CRM_Redis_Pass_2025_Secure!`
- Попробуй из терминала:
```bash
redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING
```
### ❌ События не приходят
- Убедись что файл добавлен **в правильный bucket**
- Убедись что файл **в нужной папке** (если указан Prefix)
- Подожди 30 секунд для polling цикла
- Проверь Static Data в workflow (сохраняется ли состояние?)
### ⚠️ Слишком много событий
- Уменьши область мониторинга через `Prefix`
- Увеличь интервал до 60-120 секунд
---
## 📊 Финальная проверка
После всех шагов у тебя должно быть:
- ✅ S3 credentials сохранены в n8n
- ✅ Redis credentials сохранены в n8n
- ✅ Workflow "S3 File Monitor" импортирован
- ✅ Workflow активирован (Active = ON)
- ✅ Тестовый файл загружен в S3
- ✅ Событие пришло в Redis канал `crm:file:events`
- ✅ Execution в n8n показывает ✅ success
---
## 🎉 Готово!
Теперь **любые** изменения в твоём S3 bucket будут автоматически:
1. Обнаруживаться (каждые 30 сек)
2. Публиковаться в Redis (`crm:file:events`)
3. Доступны для обработки в n8n, CRM, и других сервисах
---
## 📚 Дополнительные файлы
- `S3_MONITORING_GUIDE.md` - полное руководство
- `ARCHITECTURE.md` - схема архитектуры
- `n8n_s3_monitor_workflow.json` - workflow для импорта
- `get_s3_credentials.sh` - скрипт для получения credentials
---
## 🆘 Нужна помощь?
Если что-то не работает:
1. Проверь логи n8n executions
2. Проверь Redis подключение
3. Проверь S3 credentials
4. Перечитай `S3_MONITORING_GUIDE.md`
**Удачи!** 🚀

View File

@@ -0,0 +1,76 @@
#!/bin/bash
#
# Скрипт для запуска/проверки всех компонентов мониторинга файлов
#
echo "🚀 CRM File Monitoring System"
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
cd /var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage
# Проверка S3 Monitor
echo "1⃣ S3 Monitor (Docker):"
if docker ps | grep -q s3-monitor; then
echo " ✅ Работает"
docker ps --format " Статус: {{.Status}}" | grep s3-monitor
else
echo " ❌ НЕ работает"
echo " Запускаем..."
docker start s3-monitor 2>/dev/null || echo " ⚠️ Контейнер не существует, запустите вручную"
fi
echo ""
# Проверка Nextcloud Activity Monitor
echo "2⃣ Nextcloud Activity Monitor:"
if ps aux | grep -v grep | grep -q nextcloud_activity_monitor.js; then
PID=$(ps aux | grep -v grep | grep nextcloud_activity_monitor.js | awk '{print $2}')
echo " ✅ Работает (PID: $PID)"
else
echo " ❌ НЕ работает"
echo " Запускаем..."
nohup /usr/bin/nodejs nextcloud_activity_monitor.js > nextcloud_activity.log 2>&1 &
sleep 2
echo " ✅ Запущен (PID: $!)"
fi
echo ""
# Проверка Redis
echo "3⃣ Redis подключение:"
if redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' PING 2>&1 | grep -q PONG; then
echo " ✅ Redis доступен"
else
echo " ❌ Redis недоступен"
fi
echo ""
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
echo "📋 СТАТУС:"
echo ""
echo "Nextcloud Activity Monitor:"
tail -3 nextcloud_activity.log 2>/dev/null | tail -1
echo ""
echo "S3 Monitor:"
docker logs s3-monitor 2>&1 | tail -3 | tail -1
echo ""
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
echo "📚 Команды:"
echo ""
echo "Логи в реальном времени:"
echo " tail -f nextcloud_activity.log"
echo " docker logs s3-monitor -f"
echo ""
echo "Подписка на события:"
echo " redis-cli -h 147.45.146.17 -p 6379 -a 'CRM_Redis_Pass_2025_Secure!' SUBSCRIBE crm:file:events"
echo ""
echo "Документация:"
echo " cat README.md"
echo " cat PRODUCTION_READY.md"
echo ""

View File

@@ -0,0 +1,23 @@
<?php
/**
* ПРОСТОЙ Прокси для скачивания файла из S3
* Просто отдаём публичный URL - S3 сам разберётся
*/
$s3Path = isset($_GET['path']) ? $_GET['path'] : '';
if (empty($s3Path)) {
http_response_code(400);
die('Missing path parameter');
}
// Формируем публичный S3 URL
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
error_log("download_s3_file.php: Redirecting to: $s3Url");
// РЕДИРЕКТИМ на S3 напрямую
header('Location: ' . $s3Url);
exit;
?>

View File

@@ -0,0 +1,40 @@
<?php
/**
* Быстрая индексация одного файла в Nextcloud
*/
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$path = $input['path'] ?? '';
if (empty($path)) {
echo json_encode(['success' => false, 'error' => 'Missing path']);
exit;
}
// Формируем Nextcloud путь
$ncPath = '/admin/files/crm/' . $path;
// Запускаем сканирование
$command = "docker exec -u www-data nextcloud-fresh php occ files:scan --path=" . escapeshellarg($ncPath) . " 2>&1";
exec($command, $output, $returnCode);
if ($returnCode === 0) {
echo json_encode([
'success' => true,
'message' => 'File indexed successfully',
'output' => implode("\n", $output)
]);
} else {
echo json_encode([
'success' => false,
'error' => 'Indexing failed',
'output' => implode("\n", $output)
]);
}
?>

View File

@@ -0,0 +1,103 @@
<?php
/**
* OnlyOffice Callback для сохранения файлов в S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
// Логируем все запросы
$input = file_get_contents('php://input');
$data = json_decode($input, true);
error_log("=== ONLYOFFICE CALLBACK ===");
error_log("Method: " . $_SERVER['REQUEST_METHOD']);
error_log("Body: " . $input);
// OnlyOffice отправляет POST с JSON данными
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
$status = $data['status'] ?? 0;
$key = $data['key'] ?? 'unknown';
error_log("Callback Status: $status, Key: $key");
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
if ($status == 2 && isset($data['url'])) {
$downloadUrl = $data['url'];
error_log("File saved! Download URL: " . $downloadUrl);
try {
// Скачиваем изменённый файл от OnlyOffice
$fileContent = file_get_contents($downloadUrl);
if ($fileContent === false) {
error_log("Failed to download file from OnlyOffice");
http_response_code(500);
echo json_encode(['error' => 1]);
exit;
}
error_log("Downloaded file: " . strlen($fileContent) . " bytes");
// Извлекаем путь к файлу из documentKey
// В $key хранится md5($s3Path . '_' . $version)
// Нам нужен оригинальный путь, который мы должны хранить отдельно
// ВРЕМЕННО: Сохраняем в отдельную папку в S3 для отладки
// TODO: Нужно связать documentKey с оригинальным путём файла
// Инициализируем S3 клиент
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// ВРЕМЕННОЕ РЕШЕНИЕ: Сохраняем в папку /onlyoffice_saved/
$savedPath = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
$result = $s3Client->putObject([
'Bucket' => $bucket,
'Key' => $savedPath,
'Body' => $fileContent,
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]);
error_log("File saved to S3: " . $savedPath);
error_log("S3 Response: " . json_encode($result->toArray()));
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
} catch (Exception $e) {
error_log("Error saving file to S3: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
exit;
}
}
// Другие статусы (1 = открыт, 4 = закрыт и т.д.)
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
}
// Для всех остальных запросов - 200 OK
http_response_code(200);
echo json_encode(['error' => 0]);
?>

View File

@@ -0,0 +1,121 @@
<?php
/**
* OnlyOffice Callback v2 с сохранением в оригинальный файл S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
$input = file_get_contents('php://input');
$data = json_decode($input, true);
error_log("=== ONLYOFFICE CALLBACK V2 ===");
error_log("Body: " . $input);
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($data)) {
$status = $data['status'] ?? 0;
$key = $data['key'] ?? 'unknown';
error_log("Status: $status, Key: $key");
// Status 2 = файл сохранён, нужно скачать и загрузить в S3
if ($status == 2 && isset($data['url'])) {
$downloadUrl = $data['url'];
error_log("File saved! Downloading from: " . $downloadUrl);
try {
// Подключаемся к Redis чтобы узнать оригинальный путь
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => EnvLoader::getRequired('REDIS_HOST'),
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
]);
// Получаем маппинг
$mapping = $redis->get("crm:onlyoffice:key:$key");
if (!$mapping) {
error_log("ERROR: No mapping found for key $key");
// Сохраняем в резервную папку
$s3Path = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
} else {
$mappingData = json_decode($mapping, true);
$s3Path = $mappingData['s3_path'];
error_log("Found mapping: $key$s3Path");
}
// Скачиваем файл от OnlyOffice
$fileContent = file_get_contents($downloadUrl);
if ($fileContent === false) {
throw new Exception("Failed to download file from OnlyOffice");
}
error_log("Downloaded: " . strlen($fileContent) . " bytes");
// Инициализируем S3 клиент
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// Загружаем в S3 (ПЕРЕЗАПИСЫВАЕМ оригинальный файл!)
$result = $s3Client->putObject([
'Bucket' => $bucket,
'Key' => $s3Path,
'Body' => $fileContent,
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Metadata' => [
'saved_by' => 'onlyoffice',
'saved_at' => date('Y-m-d H:i:s')
]
]);
error_log("✅ File saved to S3: $s3Path");
// Публикуем событие в Redis
$redis->publish('crm:file:events', json_encode([
'type' => 'file_modified',
'source' => 'onlyoffice',
'timestamp' => date('c'),
'path' => $s3Path,
'size' => strlen($fileContent),
'action' => 'updated_via_onlyoffice'
]));
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
} catch (Exception $e) {
error_log("ERROR: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 1, 'message' => $e->getMessage()]);
exit;
}
}
// Другие статусы
http_response_code(200);
echo json_encode(['error' => 0]);
exit;
}
http_response_code(200);
echo json_encode(['error' => 0]);
?>

View File

@@ -1,110 +1,237 @@
<?php
/**
* Простой редирект на файл в Nextcloud БЕЗ CSRF проверок
* Использует FilePathManager для новой структуры файлов
* ФИНАЛ: OnlyOffice + Pre-signed S3 URL
* Теперь с CORS и правильными настройками!
*/
// Включаем отображение ошибок
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Подключаем конфигурацию и FilePathManager
require_once '/var/www/fastuser/data/www/crm.clientright.ru/config.inc.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/file_storage/FilePathManager.php';
// Получаем параметры
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
// Если fileName содержит полный URL S3, извлекаем путь к файлу
$ncPath = '';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
// Декодируем URL
$fileName = urldecode($fileName);
// Извлекаем путь после bucket ID
// Формат: https://s3.twcstorage.ru/BUCKET_ID/crm2/CRM_Active_Files/...
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
// Nextcloud путь = /crm/ + s3_path
$ncPath = '/crm/' . $s3Path;
}
}
if (empty($ncPath)) {
die(" Ошибка: Не удалось извлечь путь из URL: $fileName");
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Настройки Nextcloud
$nextcloudUrl = 'https://office.clientright.ru:8443';
$username = 'admin';
$password = 'office';
// Извлекаем расширение файла
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
// Вспомогательная функция: кодирование пути по сегментам (WebDAV)
$encodePath = function(array $segments) {
return implode('/', array_map('rawurlencode', $segments));
};
// ПРЯМОЙ S3 URL (bucket публичный, CORS настроен!)
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
// Получаем fileId через WebDAV PROPFIND
$fileId = null;
$propfindUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath;
// Генерируем версию и ключ документа
$version = time();
// СЛУЧАЙНЫЙ ключ при каждом запросе, чтобы OnlyOffice не использовал кеш!
$documentKey = md5($s3Path . '_' . $version);
error_log("Nextcloud Editor: PROPFIND -> {$propfindUrl}");
// ПРЯМОЙ S3 URL (bucket публичный, поэтому pre-signed URL не нужен!)
// Bucket поддерживает Range requests и CORS из коробки
$fileUrl = $s3Url;
// XML запрос для получения fileid
$xmlRequest = '<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:fileid/>
</d:prop>
</d:propfind>';
// ОТЛАДКА: Логируем все параметры
error_log("=== OPEN FILE DEBUG ===");
error_log("S3 Path: " . $s3Path);
error_log("File URL: " . $fileUrl);
error_log("File extension: " . $ext);
error_log("Document Key (unique): " . $documentKey);
error_log("Version: " . $version);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $propfindUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Depth: 0',
'Content-Type: application/xml'
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
$fileBasename = basename($s3Path);
$fileType = getFileType($ext);
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
if ($response === false) {
error_log("Nextcloud Editor: Ошибка cURL: " . $curlError);
} else {
error_log("Nextcloud Editor: HTTP код: {$httpCode}");
if ($httpCode === 207 && preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
$fileId = (int)$matches[1];
error_log("Nextcloud Editor: Получен fileId: {$fileId}");
} else {
error_log("Nextcloud Editor: Файл не найден по пути: {$ncPath} (HTTP {$httpCode})");
}
if (!in_array($ext, $officeFormats)) {
header('Location: ' . $s3Url);
exit;
}
if (!$fileId) {
$errorMsg = "❌ Ошибка: Не удалось получить fileId для файла {$fileName}";
error_log("Nextcloud Editor ERROR: " . $errorMsg);
die($errorMsg);
}
// Формируем URL для Nextcloud
// РАБОЧИЙ ФОРМАТ - редирект на файл с автооткрытием редактора!
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true';
// Логирование
error_log("Nextcloud Editor: Redirect to $redirectUrl for file (ID: $fileId)");
// Делаем редирект
header('Location: ' . $redirectUrl);
exit;
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?php echo htmlspecialchars($fileBasename); ?></title>
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
}
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="editor"></div>
<script>
// Отладка в консоль
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
console.log('🔗 S3 URL:', <?php echo json_encode($fileUrl); ?>);
console.log('🔑 Document Key (unique):', <?php echo json_encode($documentKey); ?>);
console.log('✅ Standalone OnlyOffice (9443) + Direct S3 URL!');
new DocsAPI.DocEditor("editor", {
"documentType": "<?php echo $fileType; ?>",
"document": {
"fileType": "<?php echo $ext; ?>",
"key": "<?php echo $documentKey; ?>",
"title": <?php echo json_encode($fileBasename); ?>,
"url": <?php echo json_encode($fileUrl); ?>,
"permissions": {
"comment": true,
"download": true,
"edit": true,
"print": true,
"review": true
}
},
"editorConfig": {
"mode": "edit",
"lang": "ru",
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php",
"user": {
"id": "user_<?php echo $recordId ?? 'guest'; ?>",
"name": "CRM User"
},
"customization": {
"autosave": true,
"chat": false,
"comments": true,
"compactHeader": false,
"compactToolbar": false,
"help": true,
"hideRightMenu": false,
"logo": {
"image": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png",
"imageEmbedded": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png"
},
"zoom": 100
}
},
"height": "100%",
"width": "100%",
"type": "desktop",
"events": {
"onReady": function() {
console.log('✅ Editor ready!');
},
"onDocumentReady": function() {
console.log('✅ Document loaded!');
},
"onError": function(event) {
console.error('❌ OnlyOffice Error FULL:', JSON.stringify(event, null, 2));
console.error('Event data:', event.data);
console.error('Error code:', event.data.errorCode);
console.error('Error description:', event.data.errorDescription);
// Тестируем доступность URL из браузера
console.log('🧪 Testing S3 URL from browser...');
fetch(<?php echo json_encode($fileUrl); ?>, { method: 'HEAD' })
.then(response => {
console.log('✅ Browser can access S3:', response.status);
})
.catch(error => {
console.error('❌ Browser CANNOT access S3:', error);
});
alert('Ошибка загрузки документа:\n\n' +
'Code: ' + event.data.errorCode + '\n' +
'Description: ' + event.data.errorDescription + '\n\n' +
'Используется Pre-signed URL из S3\n\n' +
'Смотри консоль браузера (F12) для деталей!');
},
"onWarning": function(event) {
console.warn('⚠️ OnlyOffice Warning:', event);
}
}
});
</script>
</body>
</html>
<?php
function getFileType($ext) {
if (in_array($ext, ['doc', 'docx'])) return 'word';
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
return 'word';
}
function generatePresignedUrl($s3Key, $expirationSeconds) {
try {
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// КЛЮЧ: Минимальные параметры = правильная подпись!
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => $bucket,
'Key' => $s3Key
]);
$request = $s3Client->createPresignedRequest($cmd, "+{$expirationSeconds} seconds");
return (string)$request->getUri();
} catch (Exception $e) {
error_log("Pre-signed URL error: " . $e->getMessage());
return null;
}
}
function getContentType($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$types = [
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
];
return $types[$ext] ?? 'application/octet-stream';
}
?>

View File

@@ -0,0 +1,58 @@
<?php
/**
* Открытие файлов через Collabora (вместо OnlyOffice)
* Collabora работает через Nextcloud WebDAV
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Nextcloud path (убираем 'crm2/')
$ncPath = str_replace('crm2/', '', $s3Path);
$fileBasename = basename($ncPath);
// Nextcloud URL
$nextcloudUrl = 'https://office.clientright.ru:8443';
$webdavPath = '/crm/crm2/' . $ncPath;
// Открываем напрямую в Nextcloud Files - Collabora откроется автоматически!
$dirPath = dirname($webdavPath);
$redirectUrl = $nextcloudUrl . '/apps/files/?dir=' . urlencode($dirPath) . '&openfile=' . urlencode($fileBasename);
error_log("=== COLLABORA OPEN ===");
error_log("S3 Path: " . $s3Path);
error_log("NC WebDAV Path: " . $webdavPath);
error_log("Redirect URL: " . $redirectUrl);
// Редиректим в Nextcloud
header('Location: ' . $redirectUrl);
exit;
?>

View File

@@ -0,0 +1,169 @@
<?php
/**
* OnlyOffice Standalone + S3 Direct URL
* С сохранением обратно в S3
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : 'unknown';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Извлекаем расширение файла
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
// ПРЯМОЙ S3 URL (bucket публичный)
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
// Генерируем уникальный ключ документа
$version = time();
$documentKey = md5($s3Path . '_' . $version);
// ВАЖНО: Сохраняем маппинг documentKey → S3 путь в Redis
try {
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => EnvLoader::getRequired('REDIS_HOST'),
'port' => (int)EnvLoader::getRequired('REDIS_PORT'),
'password' => EnvLoader::getRequired('REDIS_PASSWORD')
]);
// Сохраняем на 24 часа (TTL = срок действия документа)
$redis->setex("crm:onlyoffice:key:$documentKey", 86400, json_encode([
's3_path' => $s3Path,
'record_id' => $recordId,
'created_at' => time()
]));
error_log("Redis: Saved mapping for key $documentKey$s3Path");
} catch (Exception $e) {
error_log("Redis error: " . $e->getMessage());
}
$fileBasename = basename($s3Path);
$fileType = getFileType($ext);
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
if (!in_array($ext, $officeFormats)) {
header('Location: ' . $s3Url);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?php echo htmlspecialchars($fileBasename); ?></title>
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="editor"></div>
<script>
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
console.log('🔗 S3 URL:', <?php echo json_encode($s3Url); ?>);
console.log('🔑 Document Key:', <?php echo json_encode($documentKey); ?>);
console.log('✅ Standalone OnlyOffice + Redis mapping!');
new DocsAPI.DocEditor("editor", {
"documentType": "<?php echo $fileType; ?>",
"document": {
"fileType": "<?php echo $ext; ?>",
"key": "<?php echo $documentKey; ?>",
"title": <?php echo json_encode($fileBasename); ?>,
"url": <?php echo json_encode($s3Url); ?>,
"permissions": {
"comment": true,
"download": true,
"edit": true,
"print": true,
"review": true
}
},
"editorConfig": {
"mode": "edit",
"lang": "ru",
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback_v2.php",
"user": {
"id": "user_<?php echo $recordId; ?>",
"name": "CRM User"
},
"customization": {
"autosave": true,
"compactHeader": false,
"compactToolbar": false
}
},
"height": "100%",
"width": "100%",
"type": "desktop",
"events": {
"onReady": function() {
console.log('✅ Editor ready!');
},
"onDocumentReady": function() {
console.log('✅ Document loaded!');
},
"onError": function(event) {
console.error('❌ Error:', event.data);
alert('Ошибка: ' + event.data.errorDescription);
}
}
});
</script>
</body>
</html>
<?php
function getFileType($ext) {
if (in_array($ext, ['doc', 'docx'])) return 'word';
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
return 'word';
}
?>

View File

@@ -0,0 +1,121 @@
<?php
/**
* S3 Proxy для OnlyOffice
* Проксирует запросы к S3, чтобы OnlyOffice мог загружать файлы
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 0);
$path = isset($_GET['path']) ? $_GET['path'] : '';
if (empty($path)) {
http_response_code(400);
die('Path parameter is required');
}
// CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Max-Age: 3600');
http_response_code(200);
exit;
}
// Для HEAD запросов - только headers, без body
$isHeadRequest = ($_SERVER['REQUEST_METHOD'] === 'HEAD');
// Формируем URL к S3
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $path;
// Проверяем Range header (для OnlyOffice partial requests)
$rangeHeader = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : '';
error_log("S3 Proxy: Request from: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
error_log("S3 Proxy: Downloading: " . $s3Url);
if ($rangeHeader) {
error_log("S3 Proxy: Range request: " . $rangeHeader);
}
// СНАЧАЛА скачиваем в буфер
$ch = curl_init($s3Url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // ← ВАЖНО: В БУФЕР!
curl_setopt($ch, CURLOPT_HEADER, true); // ← Получаем headers
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
// Для HEAD запросов - только headers
if ($isHeadRequest) {
curl_setopt($ch, CURLOPT_NOBODY, true);
}
// Если есть Range header - передаём его в S3!
if ($rangeHeader) {
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Range: ' . $rangeHeader]);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$error = curl_error($ch);
curl_close($ch);
// Проверяем ПРЕЖДЕ чем отправлять что-либо
// 200 = полный файл, 206 = частичный (Range request)
if ($response === false || ($httpCode !== 200 && $httpCode !== 206)) {
error_log("S3 Proxy ERROR: HTTP $httpCode, cURL error: $error");
header('Access-Control-Allow-Origin: *');
http_response_code($httpCode ?: 500);
die('Failed to fetch file from S3');
}
// Разделяем headers и body
$headersText = substr($response, 0, $headerSize);
$body = $isHeadRequest ? '' : substr($response, $headerSize); // Для HEAD body пустой
// Парсим headers
$headers = explode("\r\n", $headersText);
foreach ($headers as $header) {
if (strpos($header, ':') !== false) {
list($name, $value) = explode(':', $header, 2);
$name = strtolower(trim($name));
$value = trim($value);
// Пробрасываем нужные headers
if (in_array($name, ['content-type', 'content-length', 'content-range', 'accept-ranges', 'etag', 'last-modified'])) {
header($name . ': ' . $value);
}
}
}
// CORS headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Expose-Headers: Content-Range, Accept-Ranges');
// Устанавливаем правильный HTTP код (206 для partial content)
if ($httpCode === 206) {
http_response_code(206);
} else {
http_response_code(200);
}
// Отправляем body только для GET запросов (не для HEAD)
if (!$isHeadRequest) {
echo $body;
error_log("S3 Proxy: Success! Sent " . strlen($body) . " bytes");
} else {
error_log("S3 Proxy: HEAD request completed");
}
?>

View File

@@ -0,0 +1,31 @@
version: '3.8'
services:
onlyoffice-standalone:
image: onlyoffice/documentserver:latest
container_name: onlyoffice-standalone
restart: unless-stopped
ports:
- "127.0.0.1:8083:80" # Новый порт (8081 и 8082 заняты)
environment:
- JWT_ENABLED=false
- JWT_SECRET=
- WOPI_ENABLED=false
volumes:
- onlyoffice-standalone-data:/var/www/onlyoffice/Data
- onlyoffice-standalone-logs:/var/log/onlyoffice
- onlyoffice-standalone-fonts:/usr/share/fonts/truetype/custom
- onlyoffice-standalone-forgotten:/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten
networks:
- crm-network
volumes:
onlyoffice-standalone-data:
onlyoffice-standalone-logs:
onlyoffice-standalone-fonts:
onlyoffice-standalone-forgotten:
networks:
crm-network:
name: crm-network

View File

@@ -0,0 +1,48 @@
#!/bin/bash
echo "🔑 S3 Credentials для n8n"
echo "════════════════════════════════════════════════════════════════════════════════"
echo ""
# Получаем credentials из Nextcloud
docker exec nextcloud-fresh php occ files_external:list --output=json 2>/dev/null | jq -r '
.[0].configuration |
"📦 Bucket: \(.bucket)
🔑 Access Key: \(.key)
🔐 Secret Key: \(.secret)
🌐 Endpoint: \(.hostname)
🗺️ Region: \(.region)
════════════════════════════════════════════════════════════════════════════════
📋 Для n8n AWS S3 Credentials:
────────────────────────────────────────────────────────────────────────────────
Access Key ID: \(.key)
Secret Access Key: \(.secret)
Region: \(.region)
Custom Endpoints: ✅ ВКЛЮЧИТЬ
S3 Endpoint: https://\(.hostname)
Force Path Style: ✅ ВКЛЮЧИТЬ
────────────────────────────────────────────────────────────────────────────────
📋 Для n8n Environment Variables:
────────────────────────────────────────────────────────────────────────────────
S3_BUCKET=\(.bucket)
S3_ENDPOINT=https://\(.hostname)
S3_REGION=\(.region)
────────────────────────────────────────────────────────────────────────────────
"
'
echo ""
echo "📋 Redis Credentials для n8n:"
echo "────────────────────────────────────────────────────────────────────────────────"
echo "Host: 147.45.146.17"
echo "Port: 6379"
echo "Password: CRM_Redis_Pass_2025_Secure!"
echo "Database: 0"
echo "────────────────────────────────────────────────────────────────────────────────"
echo ""
echo "✅ Готово! Скопируй эти данные в n8n"

View File

@@ -0,0 +1,166 @@
<?php
/**
* Простая миграция одного проекта в новую структуру
* Использование: php migrate_single_project.php PROJECT_ID
*/
require_once(__DIR__ . '/../../config.inc.php');
require_once(__DIR__ . '/../../include/database/PearDatabase.php');
$adb = PearDatabase::getInstance();
// Получаем ID проекта
$projectId = isset($argv[1]) ? (int)$argv[1] : null;
if (!$projectId) {
echo "❌ Укажите ID проекта!\n";
echo "Использование: php migrate_single_project.php PROJECT_ID\n";
exit(1);
}
echo "🔄 МИГРАЦИЯ ПРОЕКТА $projectId\n";
echo "==========================================\n\n";
// Получаем информацию о проекте
$result = $adb->pquery("SELECT p.projectname FROM vtiger_project p WHERE p.projectid = ?", [$projectId]);
if ($adb->num_rows($result) == 0) {
echo "❌ Проект не найден!\n";
exit(1);
}
$projectName = $adb->query_result($result, 0, 'projectname');
echo "📁 Проект: $projectName\n\n";
// Функция очистки имени файла
function sanitizeName($name) {
// Транслитерация
$translitMap = [
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
];
$name = strtr($name, $translitMap);
$name = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $name);
$name = preg_replace('/_+/', '_', $name);
$name = trim($name, '_');
if (strlen($name) > 100) {
$name = substr($name, 0, 100);
}
return $name;
}
$sanitizedName = sanitizeName($projectName);
$newFolder = "Documents/Project/{$sanitizedName}_{$projectId}";
echo "📁 Новая папка: $newFolder\n\n";
// Получаем все документы проекта
$result = $adb->pquery(
"SELECT n.notesid, n.title, n.filename, n.s3_key, n.filelocationtype
FROM vtiger_notes n
JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid
JOIN vtiger_crmentity e ON e.crmid = n.notesid
WHERE snr.crmid = ? AND e.deleted = 0 AND n.filelocationtype = 'E'
ORDER BY n.notesid",
[$projectId]
);
$total = $adb->num_rows($result);
echo "📊 Найдено документов: $total\n\n";
if ($total == 0) {
echo "✅ Нет документов для миграции\n";
exit(0);
}
$migrated = 0;
$errors = 0;
while ($doc = $adb->fetch_array($result)) {
$notesid = $doc['notesid'];
$title = $doc['title'];
$oldS3Key = $doc['s3_key'];
echo "[$migrated/$total] Документ: $title (ID: $notesid)\n";
echo " Старый s3_key: $oldS3Key\n";
// Извлекаем имя файла и расширение
$oldFilename = basename($oldS3Key);
$pathInfo = pathinfo($oldFilename);
$extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
// Новое имя файла: file_docID_название.ext
$newFilename = "file_{$notesid}_{$pathInfo['filename']}{$extension}";
// Новый путь в S3
$newS3Key = "{$newFolder}/{$newFilename}";
$newNcPath = "/crm/crm2/CRM_Active_Files/{$newFolder}/{$newFilename}";
// Новый URL
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$newUrl = "https://s3.twcstorage.ru/{$bucket}/crm2/CRM_Active_Files/{$newS3Key}";
echo " Новый s3_key: $newS3Key\n";
echo " Новый nc_path: $newNcPath\n";
// Копируем файл в S3 (используем aws s3 cp)
$oldKey = "crm2/CRM_Active_Files/" . $oldS3Key;
$newKey = "crm2/CRM_Active_Files/" . $newS3Key;
$copyCmd = "aws s3 cp " .
"s3://{$bucket}/{$oldKey} " .
"s3://{$bucket}/{$newKey} " .
"--endpoint-url https://s3.twcstorage.ru " .
"--region ru-1 2>&1";
echo " Копирование в S3...\n";
exec($copyCmd, $output, $returnCode);
if ($returnCode !== 0) {
echo " ❌ ОШИБКА копирования: " . implode("\n", $output) . "\n";
$errors++;
continue;
}
echo " ✅ Скопировано в S3\n";
// Обновляем БД
$updateResult = $adb->pquery(
"UPDATE vtiger_notes
SET s3_key = ?, nc_path = ?, filename = ?
WHERE notesid = ?",
[$newS3Key, $newNcPath, $newUrl, $notesid]
);
if ($updateResult) {
echo " ✅ БД обновлена\n";
$migrated++;
} else {
echo " ❌ ОШИБКА обновления БД\n";
$errors++;
}
echo "\n";
}
echo "==========================================\n";
echo "✅ МИГРАЦИЯ ЗАВЕРШЕНА!\n";
echo "Обработано: $total\n";
echo "Мигрировано: $migrated\n";
echo "Ошибок: $errors\n";

View File

@@ -0,0 +1,170 @@
{
"name": "Nextcloud Activity Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "seconds",
"secondsInterval": 30
}
]
}
},
"id": "schedule",
"name": "Каждые 30 секунд",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"url": "https://office.clientright.ru:8443/ocs/v2.php/apps/activity/api/v2/activity",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "format",
"value": "json"
},
{
"name": "limit",
"value": "100"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "OCS-APIRequest",
"value": "true"
}
]
},
"options": {}
},
"id": "http-request",
"name": "Get Nextcloud Activities",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [450, 300],
"credentials": {
"httpBasicAuth": {
"id": "3",
"name": "Nextcloud Admin"
}
}
},
{
"parameters": {
"jsCode": "// Получаем последний обработанный activity_id из Static Data\nconst staticData = getWorkflowStaticData('node');\nlet lastProcessedId = staticData.lastActivityId || 0;\n\nconst activities = $input.item.json.ocs.data;\nconst fileEvents = [];\n\n// Типы событий которые нас интересуют\nconst relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];\n\n// Фильтруем и обрабатываем события\nfor (const activity of activities) {\n // Пропускаем уже обработанные\n if (activity.activity_id <= lastProcessedId) {\n continue;\n }\n \n // Только файловые события\n if (!relevantTypes.includes(activity.type)) {\n continue;\n }\n \n // РАЗБИВАЕМ агрегированные события!\n // Если есть objects - создаём событие для каждого файла\n if (activity.objects && typeof activity.objects === 'object') {\n const fileIds = Object.keys(activity.objects);\n \n for (const fileId of fileIds) {\n const filePath = activity.objects[fileId];\n \n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: parseInt(fileId),\n path: filePath,\n filename: filePath ? filePath.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n } else {\n // Одиночное событие\n fileEvents.push({\n json: {\n type: activity.type,\n source: 'nextcloud_activity',\n timestamp: activity.datetime,\n file_id: activity.object_id,\n path: activity.object_name,\n filename: activity.object_name ? activity.object_name.split('/').pop() : null,\n user: activity.user,\n activity_id: activity.activity_id,\n action: activity.type.replace('file_', '')\n }\n });\n }\n \n // Обновляем последний ID\n if (activity.activity_id > lastProcessedId) {\n lastProcessedId = activity.activity_id;\n }\n}\n\n// Сохраняем последний обработанный ID\nstaticData.lastActivityId = lastProcessedId;\n\n// Если новых событий нет - возвращаем пустой массив\nif (fileEvents.length === 0) {\n return [];\n}\n\nreturn fileEvents;"
},
"id": "process-activities",
"name": "Process & Filter Events",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.filename}}",
"operation": "isNotEmpty"
}
]
}
},
"id": "filter",
"name": "Есть новые события?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [850, 300]
},
{
"parameters": {
"operation": "publish",
"channel": "crm:file:events",
"value": "={{JSON.stringify($json)}}",
"keyType": "automatic"
},
"id": "redis-publish",
"name": "Publish to Redis",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [1050, 200],
"credentials": {
"redis": {
"id": "2",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"content": "=📢 Nextcloud Event:\n**Type:** {{$json.type}}\n**File:** {{$json.filename}}\n**Path:** {{$json.path}}\n**User:** {{$json.user}}\n**Time:** {{$json.timestamp}}",
"options": {}
},
"id": "logger",
"name": "Log Event (optional)",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 400]
}
],
"connections": {
"schedule": {
"main": [
[
{
"node": "http-request",
"type": "main",
"index": 0
}
]
]
},
"http-request": {
"main": [
[
{
"node": "process-activities",
"type": "main",
"index": 0
}
]
]
},
"process-activities": {
"main": [
[
{
"node": "filter",
"type": "main",
"index": 0
}
]
]
},
"filter": {
"main": [
[
{
"node": "redis-publish",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,174 @@
{
"name": "S3 Event Processor",
"nodes": [
{
"parameters": {
"operation": "subscribe",
"channel": "crm:file:events"
},
"id": "redis-subscribe",
"name": "Redis Subscribe",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [250, 300],
"credentials": {
"redis": {
"id": "CRM_REDIS_ID",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"jsCode": "// Парсим JSON из Redis message\nconst items = [];\n\nfor (const item of $input.all()) {\n const message = item.json.message;\n \n // Если message это строка - парсим\n let parsedMessage = message;\n if (typeof message === 'string') {\n parsedMessage = JSON.parse(message);\n }\n \n items.push({\n json: parsedMessage\n });\n}\n\nreturn items;"
},
"id": "parse-json",
"name": "Parse Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [450, 300]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.type }}",
"rightValue": "file_created",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "filter-created",
"name": "Только новые файлы",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"options": {},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.filename }}",
"rightValue": ".xlsx",
"operator": {
"type": "string",
"operation": "endsWith"
}
}
],
"combinator": "or"
}
},
"id": "filter-xlsx",
"name": "Только XLSX",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [850, 200]
},
{
"parameters": {
"conditions": {
"options": {},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.filename }}",
"rightValue": ".pdf",
"operator": {
"type": "string",
"operation": "endsWith"
}
}
],
"combinator": "or"
}
},
"id": "filter-pdf",
"name": "Только PDF",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [850, 400]
},
{
"parameters": {
"content": "=📊 **XLSX файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать файл из S3\n- Обработать данные\n- Загрузить в CRM\n- Отправить уведомление",
"height": 312,
"width": 389
},
"id": "process-xlsx",
"name": "Обработка XLSX",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 80]
},
{
"parameters": {
"content": "=📄 **PDF файл обнаружен!**\n\n**Имя:** {{ $json.filename }}\n**Путь:** {{ $json.path }}\n**Размер:** {{ $json.size }} bytes\n**Время:** {{ $json.timestamp }}\n\n---\n\nЗдесь можно:\n- Скачать PDF из S3\n- OCR распознавание\n- Извлечь данные\n- Создать документ в CRM",
"height": 312,
"width": 389
},
"id": "process-pdf",
"name": "Обработка PDF",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1050, 320]
}
],
"connections": {
"redis-subscribe": {
"main": [
[
{
"node": "parse-json",
"type": "main",
"index": 0
}
]
]
},
"parse-json": {
"main": [
[
{
"node": "filter-created",
"type": "main",
"index": 0
}
]
]
},
"filter-created": {
"main": [
[
{
"node": "filter-xlsx",
"type": "main",
"index": 0
},
{
"node": "filter-pdf",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,179 @@
{
"name": "S3 File Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "seconds",
"secondsInterval": 30
}
]
}
},
"id": "schedule",
"name": "Каждые 30 секунд",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"operation": "getAll",
"bucketName": "={{$env.S3_BUCKET}}",
"returnAll": true,
"options": {
"prefix": ""
}
},
"id": "s3-list",
"name": "List S3 Files",
"type": "n8n-nodes-base.awsS3",
"typeVersion": 1,
"position": [450, 300],
"credentials": {
"aws": {
"id": "1",
"name": "TWC S3"
}
}
},
{
"parameters": {
"functionCode": "// Храним состояние файлов в Static Data\nconst currentState = $node[\"s3-list\"].json;\nconst previousState = $getWorkflowStaticData('node') || {};\nconst events = [];\n\n// Проверяем новые и изменённые файлы\nfor (const file of currentState) {\n const key = file.Key;\n const etag = file.ETag;\n \n if (!previousState[key]) {\n // Новый файл\n events.push({\n type: 'file_created',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n } else if (previousState[key].ETag !== etag) {\n // Файл изменён\n events.push({\n type: 'file_modified',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop(),\n size: file.Size,\n etag: etag,\n last_modified: file.LastModified\n });\n }\n \n previousState[key] = { ETag: etag, Size: file.Size };\n}\n\n// Проверяем удалённые файлы\nconst currentKeys = currentState.map(f => f.Key);\nfor (const key in previousState) {\n if (!currentKeys.includes(key)) {\n events.push({\n type: 'file_deleted',\n source: 's3_monitor',\n timestamp: new Date().toISOString(),\n path: key,\n filename: key.split('/').pop()\n });\n delete previousState[key];\n }\n}\n\n// Сохраняем новое состояние\n$setWorkflowStaticData(previousState);\n\nreturn events.map(event => ({ json: event }));"
},
"id": "detect-changes",
"name": "Detect Changes",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [650, 300]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.type }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
}
},
"id": "filter",
"name": "Есть изменения?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [850, 300]
},
{
"parameters": {
"operation": "publish",
"channel": "crm:file:events",
"value": "={{JSON.stringify($json)}}",
"keyType": "automatic",
"expire": false,
"expireAfter": 86400
},
"id": "redis-publish",
"name": "Publish to Redis",
"type": "n8n-nodes-base.redis",
"typeVersion": 1,
"position": [1050, 200],
"credentials": {
"redis": {
"id": "2",
"name": "CRM Redis"
}
}
},
{
"parameters": {
"url": "={{$env.WEBHOOK_URL}}",
"options": {
"bodyContentType": "json"
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "event",
"value": "={{$json}}"
}
]
}
},
"id": "webhook",
"name": "Send Webhook (опционально)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [1050, 400]
}
],
"connections": {
"schedule": {
"main": [
[
{
"node": "s3-list",
"type": "main",
"index": 0
}
]
]
},
"s3-list": {
"main": [
[
{
"node": "detect-changes",
"type": "main",
"index": 0
}
]
]
},
"detect-changes": {
"main": [
[
{
"node": "filter",
"type": "main",
"index": 0
}
]
]
},
"filter": {
"main": [
[
{
"node": "redis-publish",
"type": "main",
"index": 0
},
{
"node": "webhook",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}

View File

@@ -0,0 +1,249 @@
#!/usr/bin/env node
/**
* Nextcloud Activity Monitor
* Мониторит события файлов через Activity API и публикует в Redis
*/
const https = require('https');
const Redis = require('ioredis');
const CONFIG = {
nextcloud: {
host: 'office.clientright.ru',
port: 8443,
username: 'admin',
password: 'tGHKS-3cC9m-7Hggb-65Awk-zxWQE',
auth: Buffer.from('admin:tGHKS-3cC9m-7Hggb-65Awk-zxWQE').toString('base64')
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
pollInterval: 30000, // 30 секунд
stateKey: 'crm:nextcloud:activity:state'
};
const redis = new Redis({
host: CONFIG.redis.host,
port: CONFIG.redis.port,
password: CONFIG.redis.password
});
// Хранилище последнего обработанного activity_id
let lastActivityId = 0;
// Загрузка состояния из Redis
async function loadState() {
try {
const data = await redis.get(CONFIG.stateKey);
if (data) {
const state = JSON.parse(data);
lastActivityId = state.lastActivityId || 0;
console.log(`📥 Последний обработанный activity_id: ${lastActivityId}`);
} else {
console.log('📥 Состояние пустое (первый запуск)');
}
} catch (err) {
console.error('⚠️ Ошибка загрузки состояния:', err.message);
}
}
// Сохранение состояния в Redis
async function saveState() {
try {
await redis.set(CONFIG.stateKey, JSON.stringify({ lastActivityId }));
} catch (err) {
console.error('⚠️ Ошибка сохранения состояния:', err.message);
}
}
// Получение активностей из Nextcloud API
function getActivities(limit = 100) {
return new Promise((resolve, reject) => {
const options = {
hostname: CONFIG.nextcloud.host,
port: CONFIG.nextcloud.port,
path: `/ocs/v2.php/apps/activity/api/v2/activity?format=json&limit=${limit}`,
method: 'GET',
headers: {
'Authorization': `Basic ${CONFIG.nextcloud.auth}`,
'OCS-APIRequest': 'true'
},
rejectUnauthorized: false
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const json = JSON.parse(data);
resolve(json.ocs.data || []);
} catch (err) {
reject(new Error('Ошибка парсинга JSON: ' + err.message));
}
});
});
req.on('error', (err) => {
reject(err);
});
req.setTimeout(10000, () => {
req.destroy();
reject(new Error('Timeout'));
});
req.end();
});
}
// Публикация события в Redis
async function publishEvent(event) {
console.log(`\n 📢 ${event.type.toUpperCase()}: ${event.filename}`);
console.log(` 🆔 file_id: ${event.file_id}`);
console.log(` 👤 user: ${event.user}`);
try {
await redis.publish('crm:file:events', JSON.stringify(event));
console.log(` ✅ Опубликовано в Redis`);
} catch (err) {
console.error(` ❌ Ошибка публикации:`, err.message);
}
}
// Сканирование новых активностей
async function scanActivities() {
try {
console.log(`\n🔍 Проверка новых событий... (${new Date().toISOString()})`);
const activities = await getActivities(100);
const relevantTypes = ['file_created', 'file_changed', 'file_deleted', 'file_restored'];
let newEvents = 0;
let totalFiles = 0;
// Обрабатываем активности (от новых к старым)
for (const activity of activities) {
// Пропускаем уже обработанные
if (activity.activity_id <= lastActivityId) {
continue;
}
// Только файловые события
if (!relevantTypes.includes(activity.type)) {
continue;
}
newEvents++;
// РАЗБИВАЕМ агрегированные события на отдельные файлы!
if (activity.objects && typeof activity.objects === 'object') {
// Множественное событие - разбиваем
const fileIds = Object.keys(activity.objects);
totalFiles += fileIds.length;
console.log(` 📦 Агрегированное событие: ${fileIds.length} файлов`);
for (const fileId of fileIds) {
const filePath = activity.objects[fileId];
const event = {
type: activity.type,
source: 'nextcloud_activity',
timestamp: activity.datetime,
file_id: parseInt(fileId),
path: filePath,
filename: filePath ? filePath.split('/').pop().replace(/^\//, '') : null,
user: activity.user,
activity_id: activity.activity_id,
action: activity.type.replace('file_', '')
};
await publishEvent(event);
}
} else {
// Одиночное событие
totalFiles++;
const event = {
type: activity.type,
source: 'nextcloud_activity',
timestamp: activity.datetime,
file_id: activity.object_id,
path: activity.object_name,
filename: activity.object_name ? activity.object_name.split('/').pop().replace(/^\//, '') : null,
user: activity.user,
activity_id: activity.activity_id,
action: activity.type.replace('file_', '')
};
await publishEvent(event);
}
// Обновляем последний ID
if (activity.activity_id > lastActivityId) {
lastActivityId = activity.activity_id;
}
}
// Сохраняем состояние
await saveState();
console.log(`\n✅ Сканирование завершено:`);
console.log(` 📊 Новых активностей: ${newEvents}`);
console.log(` 📁 Файлов обработано: ${totalFiles}`);
console.log(` 🆔 Последний activity_id: ${lastActivityId}`);
} catch (err) {
console.error('❌ Ошибка сканирования:', err.message);
}
}
// Запуск
async function start() {
console.log('🚀 Nextcloud Activity Monitor');
console.log('════════════════════════════════════════════════════════════════════════════════');
console.log(`📡 Nextcloud: ${CONFIG.nextcloud.host}:${CONFIG.nextcloud.port}`);
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
console.log(`🔄 Интервал: ${CONFIG.pollInterval / 1000}с`);
console.log('════════════════════════════════════════════════════════════════════════════════\n');
await loadState();
console.log('👂 Начинаем мониторинг...\n');
// Первое сканирование
await scanActivities();
// Периодическое сканирование
setInterval(scanActivities, CONFIG.pollInterval);
}
// Запуск при подключении к Redis
redis.on('connect', () => {
console.log('✅ Подключились к Redis\n');
start();
});
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err.message);
});
process.on('SIGINT', () => {
console.log('\n\n⛔ Остановка мониторинга...');
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n\n⛔ Получен сигнал SIGTERM, останавливаемся...');
redis.disconnect();
process.exit(0);
});

View File

@@ -0,0 +1,123 @@
#!/usr/bin/env node
/**
* Nextcloud Cache Updater
*
* Подписывается на Redis канал crm:file:events
* При новом файле - обновляет кеш Nextcloud для этого файла
* БЕЗ полного сканирования всей папки!
*/
const Redis = require('ioredis');
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
const CONFIG = {
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
channel: 'crm:file:events',
nextcloudContainer: 'nextcloud-fresh'
};
const redis = new Redis(CONFIG.redis);
console.log('🔄 Nextcloud Cache Updater');
console.log('==========================================');
console.log(`📡 Подписка на: ${CONFIG.channel}`);
console.log(`🐳 Nextcloud: ${CONFIG.nextcloudContainer}`);
console.log('');
// Подписка на канал
redis.subscribe(CONFIG.channel, (err, count) => {
if (err) {
console.error('❌ Ошибка подписки:', err);
process.exit(1);
}
console.log(`✅ Подписка активна (${count} каналов)`);
console.log('⏳ Ожидание событий...\n');
});
// Обработка событий
redis.on('message', async (channel, message) => {
try {
const event = JSON.parse(message);
// Логируем событие
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] 📥 Событие:`);
console.log(` Type: ${event.type}`);
console.log(` Source: ${event.source}`);
console.log(` Path: ${event.path || event.filename}`);
// Обрабатываем только создание/изменение файлов
if (!['file_created', 'file_modified', 'file_update'].includes(event.type)) {
console.log(` ⏭️ Пропуск (не файловое событие)\n`);
return;
}
// Извлекаем путь файла
let filePath = event.path || event.filename;
// Для событий из S3 Monitor - путь уже правильный
// Для событий из Nextcloud - может быть без префикса
// Формируем путь для Nextcloud
let ncPath = filePath;
if (!ncPath.startsWith('/')) {
ncPath = '/admin/files/crm/' + ncPath;
}
console.log(` 🔄 Обновление кеша Nextcloud...`);
console.log(` Путь: ${ncPath}`);
// Обновляем кеш только для этого файла
const command = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${ncPath}" 2>&1`;
try {
const { stdout, stderr } = await execPromise(command);
if (stderr && !stderr.includes('Starting scan')) {
console.log(` ⚠️ Предупреждение: ${stderr}`);
}
console.log(` ✅ Кеш обновлён`);
// Дополнительно очищаем statcache для этой папки
const dirname = ncPath.substring(0, ncPath.lastIndexOf('/'));
const clearCommand = `docker exec -u www-data ${CONFIG.nextcloudContainer} php occ files:scan --path="${dirname}" --shallow 2>&1`;
await execPromise(clearCommand);
console.log(` ✅ Родительская папка обновлена\n`);
} catch (execError) {
console.error(` ❌ Ошибка обновления: ${execError.message}\n`);
}
} catch (error) {
console.error(`❌ Ошибка обработки события:`, error.message);
console.error(` Сообщение:`, message.substring(0, 200));
console.log('');
}
});
// Обработка ошибок
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err);
});
// Graceful shutdown
process.on('SIGINT', () => {
console.log('\n\n🛑 Остановка...');
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n\n🛑 Остановка...');
redis.disconnect();
process.exit(0);
});

View File

@@ -0,0 +1,130 @@
#!/usr/bin/env node
/**
* Nextcloud FileID Indexer
*
* Индексирует fileId из Nextcloud БД в Redis для быстрого доступа
* Структура: crm:nc:fileid:{path} => fileId
*/
const mysql = require('mysql2/promise');
const Redis = require('ioredis');
const CONFIG = {
nextcloud_db: {
host: '192.168.128.3',
user: 'nextcloud',
password: 'nextcloud_password',
database: 'nextcloud'
},
redis: {
host: '147.45.146.17',
port: 6379,
password: 'CRM_Redis_Pass_2025_Secure!'
},
// Индексируем только файлы из этих папок
pathPrefixes: [
'files/crm/crm2/',
'files/crm/erv_app/'
],
indexInterval: 60000 // Обновляем индекс каждую минуту
};
const redis = new Redis(CONFIG.redis);
let connection = null;
async function connectDB() {
try {
connection = await mysql.createConnection(CONFIG.nextcloud_db);
console.log('✅ Подключились к БД Nextcloud');
} catch (err) {
console.error('❌ Ошибка подключения к БД:', err.message);
process.exit(1);
}
}
async function indexFiles() {
try {
console.log(`\n🔍 Индексация файлов... (${new Date().toISOString()})`);
let totalIndexed = 0;
for (const prefix of CONFIG.pathPrefixes) {
// Получаем все файлы из этой папки
const [rows] = await connection.execute(
'SELECT fileid, path, name, size, mtime FROM oc_filecache WHERE path LIKE ? AND mimetype != 2',
[prefix + '%']
);
console.log(` 📁 ${prefix}: найдено ${rows.length} файлов`);
// Индексируем в Redis
const pipeline = redis.pipeline();
for (const row of rows) {
const key = `crm:nc:fileid:${row.path}`;
const value = JSON.stringify({
fileId: row.fileid,
name: row.name,
size: row.size,
mtime: row.mtime
});
// Храним 24 часа (обновляется каждую минуту)
pipeline.setex(key, 86400, value);
totalIndexed++;
}
await pipeline.exec();
}
console.log(`✅ Проиндексировано: ${totalIndexed} файлов`);
} catch (err) {
console.error('❌ Ошибка индексации:', err.message);
console.error(err.stack);
}
}
async function start() {
console.log('🚀 Nextcloud FileID Indexer');
console.log('════════════════════════════════════════════════════════════════════════════════');
console.log(`🗄️ Nextcloud DB: ${CONFIG.nextcloud_db.host}/${CONFIG.nextcloud_db.database}`);
console.log(`📡 Redis: ${CONFIG.redis.host}:${CONFIG.redis.port}`);
console.log(`🔄 Интервал: ${CONFIG.indexInterval / 1000}с`);
console.log('════════════════════════════════════════════════════════════════════════════════\n');
await connectDB();
console.log('👂 Начинаем индексацию...\n');
// Первая индексация
await indexFiles();
// Периодическая индексация
setInterval(indexFiles, CONFIG.indexInterval);
}
// Запуск
redis.on('connect', () => {
console.log('✅ Подключились к Redis\n');
start();
});
redis.on('error', (err) => {
console.error('❌ Redis ошибка:', err.message);
});
process.on('SIGINT', async () => {
console.log('\n\n⛔ Остановка индексатора...');
if (connection) await connection.end();
redis.disconnect();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log('\n\n⛔ Остановка индексатора...');
if (connection) await connection.end();
redis.disconnect();
process.exit(0);
});

1
crm_extensions/file_storage/node_modules/.bin/fxparser generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../fast-xml-parser/src/cli/cli.js

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
**Note:** Version bump only for package @aws-crypto/crc32
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/crc32
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
**Note:** Version bump only for package @aws-crypto/crc32
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/crc32
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
### Bug Fixes
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
**Note:** Version bump only for package @aws-crypto/crc32
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Features
- Add AwsCrc32 Hash ([f5d7e81](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/f5d7e815fcbe0f8da1edb855fea3bd33eb1edc15))
# [1.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0...@aws-crypto/crc32@1.1.0) (2021-08-11)
### Features
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))
# [1.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@1.0.0-alpha.0...@aws-crypto/crc32@1.0.0) (2020-10-22)
**Note:** Version bump only for package @aws-crypto/crc32
# [1.0.0-alpha.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.4...@aws-crypto/crc32@1.0.0-alpha.0) (2020-02-07)
**Note:** Version bump only for package @aws-crypto/crc32
# [0.1.0-preview.4](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.4) (2020-01-16)
### Bug Fixes
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
# [0.1.0-preview.3](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.2...@aws-crypto/crc32@0.1.0-preview.3) (2019-11-15)
### Bug Fixes
- Changed package.json files to point to the right Git repo ([#9](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/9)) ([028245d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/028245d72e642ca98d82226afb300eb154503c4a)), closes [#8](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/8)
- lerna version maintains package-lock ([#14](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/14)) ([2ef29e1](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/2ef29e13779703a5c9b32e93d18918fcb33b7272)), closes [#13](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/13)
# [0.1.0-preview.2](https://github.com/aws/aws-javascript-crypto-helpers/compare/@aws-crypto/crc32@0.1.0-preview.1...@aws-crypto/crc32@0.1.0-preview.2) (2019-10-30)
### Bug Fixes
- remove /src/ from .npmignore (for sourcemaps) ([#5](https://github.com/aws/aws-javascript-crypto-helpers/issues/5)) ([ec52056](https://github.com/aws/aws-javascript-crypto-helpers/commit/ec52056))

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,16 @@
# @aws-crypto/crc32
Pure JS implementation of CRC32 https://en.wikipedia.org/wiki/Cyclic_redundancy_check
## Usage
```
import { Crc32 } from '@aws-crypto/crc32';
const crc32Digest = (new Crc32).update(buffer).digest()
```
## Test
`npm test`

View File

@@ -0,0 +1,7 @@
import { SourceData, Checksum } from "@aws-sdk/types";
export declare class AwsCrc32 implements Checksum {
private crc32;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,31 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32 = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
var index_1 = require("./index");
var AwsCrc32 = /** @class */ (function () {
function AwsCrc32() {
this.crc32 = new index_1.Crc32();
}
AwsCrc32.prototype.update = function (toHash) {
if ((0, util_1.isEmptyData)(toHash))
return;
this.crc32.update((0, util_1.convertToBuffer)(toHash));
};
AwsCrc32.prototype.digest = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32.digest())];
});
});
};
AwsCrc32.prototype.reset = function () {
this.crc32 = new index_1.Crc32();
};
return AwsCrc32;
}());
exports.AwsCrc32 = AwsCrc32;
//# sourceMappingURL=aws_crc32.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAgC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,aAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,4BAAQ"}

View File

@@ -0,0 +1,7 @@
export declare function crc32(data: Uint8Array): number;
export declare class Crc32 {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32 = exports.Crc32 = exports.crc32 = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
function crc32(data) {
return new Crc32().update(data).digest();
}
exports.crc32 = crc32;
var Crc32 = /** @class */ (function () {
function Crc32() {
this.checksum = 0xffffffff;
}
Crc32.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32;
}());
exports.Crc32 = Crc32;
// prettier-ignore
var a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookUpTable);
var aws_crc32_1 = require("./aws_crc32");
Object.defineProperty(exports, "AwsCrc32", { enumerable: true, get: function () { return aws_crc32_1.AwsCrc32; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,yCAAiD;AAEjD,SAAgB,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAFD,sBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;AAfY,sBAAK;AAiBlB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,yCAAuC;AAA9B,qGAAA,QAAQ,OAAA"}

View File

@@ -0,0 +1,7 @@
import { SourceData, Checksum } from "@aws-sdk/types";
export declare class AwsCrc32 implements Checksum {
private crc32;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,28 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __awaiter, __generator } from "tslib";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32 } from "./index";
var AwsCrc32 = /** @class */ (function () {
function AwsCrc32() {
this.crc32 = new Crc32();
}
AwsCrc32.prototype.update = function (toHash) {
if (isEmptyData(toHash))
return;
this.crc32.update(convertToBuffer(toHash));
};
AwsCrc32.prototype.digest = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, numToUint8(this.crc32.digest())];
});
});
};
AwsCrc32.prototype.reset = function () {
this.crc32 = new Crc32();
};
return AwsCrc32;
}());
export { AwsCrc32 };
//# sourceMappingURL=aws_crc32.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32.js","sourceRoot":"","sources":["../../src/aws_crc32.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;IAAA;QACU,UAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAe9B,CAAC;IAbC,yBAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEK,yBAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACxC;IAED,wBAAK,GAAL;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC3B,CAAC;IACH,eAAC;AAAD,CAAC,AAhBD,IAgBC"}

View File

@@ -0,0 +1,7 @@
export declare function crc32(data: Uint8Array): number;
export declare class Crc32 {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,103 @@
import { __values } from "tslib";
import { uint32ArrayFrom } from "@aws-crypto/util";
export function crc32(data) {
return new Crc32().update(data).digest();
}
var Crc32 = /** @class */ (function () {
function Crc32() {
this.checksum = 0xffffffff;
}
Crc32.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32;
}());
export { Crc32 };
// prettier-ignore
var a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
var lookupTable = uint32ArrayFrom(a_lookUpTable);
export { AwsCrc32 } from "./aws_crc32";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,KAAK,CAAC,IAAgB;IACpC,OAAO,IAAI,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,sBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,YAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC;AACF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}

View File

@@ -0,0 +1,32 @@
{
"name": "@aws-crypto/crc32",
"version": "5.2.0",
"scripts": {
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
"pretest": "tsc -p tsconfig.test.json",
"test": "mocha --require ts-node/register test/**/*test.ts"
},
"main": "./build/main/index.js",
"module": "./build/module/index.js",
"types": "./build/main/index.d.ts",
"repository": {
"type": "git",
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
},
"author": {
"name": "AWS Crypto Tools Team",
"email": "aws-cryptools@amazon.com",
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
},
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.0.0"
},
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
}

View File

@@ -0,0 +1,24 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SourceData, Checksum } from "@aws-sdk/types";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32 } from "./index";
export class AwsCrc32 implements Checksum {
private crc32 = new Crc32();
update(toHash: SourceData) {
if (isEmptyData(toHash)) return;
this.crc32.update(convertToBuffer(toHash));
}
async digest(): Promise<Uint8Array> {
return numToUint8(this.crc32.digest());
}
reset(): void {
this.crc32 = new Crc32();
}
}

View File

@@ -0,0 +1,92 @@
import {uint32ArrayFrom} from "@aws-crypto/util";
export function crc32(data: Uint8Array): number {
return new Crc32().update(data).digest();
}
export class Crc32 {
private checksum = 0xffffffff;
update(data: Uint8Array): this {
for (const byte of data) {
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
return this;
}
digest(): number {
return (this.checksum ^ 0xffffffff) >>> 0;
}
}
// prettier-ignore
const a_lookUpTable = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
];
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookUpTable)
export { AwsCrc32 } from "./aws_crc32";

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build/main",
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**"]
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"outDir": "build/module",
"module": "esnext",
}
}

View File

@@ -0,0 +1,76 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
**Note:** Version bump only for package @aws-crypto/crc32c
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/crc32c
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
## [2.0.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.0...v2.0.1) (2021-12-09)
**Note:** Version bump only for package @aws-crypto/crc32c
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/crc32c
## [1.2.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.1...v1.2.2) (2021-10-12)
### Bug Fixes
- **crc32c:** ie11 does not support Array.from ([#221](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/221)) ([5f49547](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/5f495472ab8988cf203e0f2a70a51f7e1fcd7e60))
## [1.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.0...v1.2.1) (2021-09-17)
**Note:** Version bump only for package @aws-crypto/crc32c
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Features
- Add AwsCrc32C Hash ([4840c83](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/4840c83bdd7c461dded777ebc45a8f99258ba21c))
## [0.2.1](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/@aws-crypto/crc32c@0.2.0...@aws-crypto/crc32c@0.2.1) (2021-08-24)
**Note:** Version bump only for package @aws-crypto/crc32c
# 0.2.0 (2021-08-11)
### Features
- Create CRC-32C implementation ([#201](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/201)) ([e43c7ec](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e43c7ecd30d6499fa696f5839ecc30502a34b8b6))

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,16 @@
# @aws-crypto/crc32c
Pure JS implementation of CRC32-C https://en.wikipedia.org/wiki/Cyclic_redundancy_check
## Usage
```
import { Crc32c } from '@aws-crypto/crc32c';
const crc32Digest = (new Crc32c).update(buffer).digest()
```
## Test
`npm test`

View File

@@ -0,0 +1,7 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class AwsCrc32c implements Checksum {
private crc32c;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,31 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32c = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
var index_1 = require("./index");
var AwsCrc32c = /** @class */ (function () {
function AwsCrc32c() {
this.crc32c = new index_1.Crc32c();
}
AwsCrc32c.prototype.update = function (toHash) {
if ((0, util_1.isEmptyData)(toHash))
return;
this.crc32c.update((0, util_1.convertToBuffer)(toHash));
};
AwsCrc32c.prototype.digest = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, (0, util_1.numToUint8)(this.crc32c.digest())];
});
});
};
AwsCrc32c.prototype.reset = function () {
this.crc32c = new index_1.Crc32c();
};
return AwsCrc32c;
}());
exports.AwsCrc32c = AwsCrc32c;
//# sourceMappingURL=aws_crc32c.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAGtC,yCAA4E;AAC5E,iCAAiC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,IAAA,kBAAW,EAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,cAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,8BAAS"}

View File

@@ -0,0 +1,7 @@
export declare function crc32c(data: Uint8Array): number;
export declare class Crc32c {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,78 @@
"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsCrc32c = exports.Crc32c = exports.crc32c = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@aws-crypto/util");
function crc32c(data) {
return new Crc32c().update(data).digest();
}
exports.crc32c = crc32c;
var Crc32c = /** @class */ (function () {
function Crc32c() {
this.checksum = 0xffffffff;
}
Crc32c.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32c.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32c;
}());
exports.Crc32c = Crc32c;
// prettier-ignore
var a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
var lookupTable = (0, util_1.uint32ArrayFrom)(a_lookupTable);
var aws_crc32c_1 = require("./aws_crc32c");
Object.defineProperty(exports, "AwsCrc32c", { enumerable: true, get: function () { return aws_crc32c_1.AwsCrc32c; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,sCAAsC;;;;AAEtC,yCAAiD;AAEjD,SAAgB,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAFD,wBAEC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,iBAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;AAfY,wBAAM;AAiBnB,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,IAAA,sBAAe,EAAC,aAAa,CAAC,CAAA;AAC/D,2CAAyC;AAAhC,uGAAA,SAAS,OAAA"}

View File

@@ -0,0 +1,7 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class AwsCrc32c implements Checksum {
private crc32c;
update(toHash: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,28 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __awaiter, __generator } from "tslib";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32c } from "./index";
var AwsCrc32c = /** @class */ (function () {
function AwsCrc32c() {
this.crc32c = new Crc32c();
}
AwsCrc32c.prototype.update = function (toHash) {
if (isEmptyData(toHash))
return;
this.crc32c.update(convertToBuffer(toHash));
};
AwsCrc32c.prototype.digest = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, numToUint8(this.crc32c.digest())];
});
});
};
AwsCrc32c.prototype.reset = function () {
this.crc32c = new Crc32c();
};
return AwsCrc32c;
}());
export { AwsCrc32c };
//# sourceMappingURL=aws_crc32c.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"aws_crc32c.js","sourceRoot":"","sources":["../../src/aws_crc32c.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAGtC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC;IAAA;QACU,WAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAehC,CAAC;IAbC,0BAAM,GAAN,UAAO,MAAkB;QACvB,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEK,0BAAM,GAAZ;;;gBACE,sBAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAC;;;KACzC;IAED,yBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC7B,CAAC;IACH,gBAAC;AAAD,CAAC,AAhBD,IAgBC"}

View File

@@ -0,0 +1,7 @@
export declare function crc32c(data: Uint8Array): number;
export declare class Crc32c {
private checksum;
update(data: Uint8Array): this;
digest(): number;
}
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,73 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { __values } from "tslib";
import { uint32ArrayFrom } from "@aws-crypto/util";
export function crc32c(data) {
return new Crc32c().update(data).digest();
}
var Crc32c = /** @class */ (function () {
function Crc32c() {
this.checksum = 0xffffffff;
}
Crc32c.prototype.update = function (data) {
var e_1, _a;
try {
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var byte = data_1_1.value;
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Crc32c.prototype.digest = function () {
return (this.checksum ^ 0xffffffff) >>> 0;
};
return Crc32c;
}());
export { Crc32c };
// prettier-ignore
var a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
var lookupTable = uint32ArrayFrom(a_lookupTable);
export { AwsCrc32c } from "./aws_crc32c";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sCAAsC;;AAEtC,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC;AAED;IAAA;QACU,aAAQ,GAAG,UAAU,CAAC;IAchC,CAAC;IAZC,uBAAM,GAAN,UAAO,IAAgB;;;YACrB,KAAmB,IAAA,SAAA,SAAA,IAAI,CAAA,0BAAA,4CAAE;gBAApB,IAAM,IAAI,iBAAA;gBACb,IAAI,CAAC,QAAQ;oBACX,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;aACtE;;;;;;;;;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAM,GAAN;QACE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACH,aAAC;AAAD,CAAC,AAfD,IAeC;;AAED,kBAAkB;AAClB,IAAM,aAAa,GAAG;IACpB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9F,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/F,CAAC;AAEF,IAAM,WAAW,GAAgB,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}

View File

@@ -0,0 +1,32 @@
{
"name": "@aws-crypto/crc32c",
"version": "5.2.0",
"scripts": {
"prepublishOnly": "tsc -p tsconfig.json && tsc -p tsconfig.module.json",
"pretest": "tsc -p tsconfig.test.json",
"test": "mocha --require ts-node/register test/**/*test.ts"
},
"main": "./build/main/index.js",
"module": "./build/module/index.js",
"types": "./build/main/index.d.ts",
"repository": {
"type": "git",
"url": "git@github.com:aws/aws-sdk-js-crypto-helpers.git"
},
"author": {
"name": "AWS Crypto Tools Team",
"email": "aws-cryptools@amazon.com",
"url": "https://docs.aws.amazon.com/aws-crypto-tools/index.html?id=docs_gateway#lang/en_us"
},
"homepage": "https://github.com/aws/aws-sdk-js-crypto-helpers/tree/master/packages/crc32c",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
"tslib": "^2.6.2"
},
"publishConfig": {
"access": "public"
},
"gitHead": "c11b171b35ec5c093364f0e0d8dc4ab1af68e748"
}

View File

@@ -0,0 +1,24 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { Checksum, SourceData } from "@aws-sdk/types";
import { convertToBuffer, isEmptyData, numToUint8 } from "@aws-crypto/util";
import { Crc32c } from "./index";
export class AwsCrc32c implements Checksum {
private crc32c = new Crc32c();
update(toHash: SourceData) {
if (isEmptyData(toHash)) return;
this.crc32c.update(convertToBuffer(toHash));
}
async digest(): Promise<Uint8Array> {
return numToUint8(this.crc32c.digest());
}
reset(): void {
this.crc32c = new Crc32c();
}
}

View File

@@ -0,0 +1,64 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {uint32ArrayFrom} from "@aws-crypto/util";
export function crc32c(data: Uint8Array): number {
return new Crc32c().update(data).digest();
}
export class Crc32c {
private checksum = 0xffffffff;
update(data: Uint8Array): this {
for (const byte of data) {
this.checksum =
(this.checksum >>> 8) ^ lookupTable[(this.checksum ^ byte) & 0xff];
}
return this;
}
digest(): number {
return (this.checksum ^ 0xffffffff) >>> 0;
}
}
// prettier-ignore
const a_lookupTable = [
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
];
const lookupTable: Uint32Array = uint32ArrayFrom(a_lookupTable)
export { AwsCrc32c } from "./aws_crc32c";

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build/main",
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**"]
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"outDir": "build/module",
"module": "esnext",
}
}

View File

@@ -0,0 +1,62 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.1.0...v5.2.0) (2023-10-16)
### Features
- support ESM artifacts in all packages ([#752](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/752)) ([e930ffb](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/e930ffba5cfef66dd242049e7d514ced232c1e3b))
# [5.1.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v5.0.0...v5.1.0) (2023-09-22)
### Bug Fixes
- Update tsc to 2.x ([#735](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/735)) ([782e0de](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/782e0de9f5fef41f694130580a69d940894b6b8c))
### Features
- Use @smithy/util-utf8 ([#730](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/730)) ([00fb851](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/00fb851ca3559d5a1f370f9256814de1210826b8)), closes [#699](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/699)
# [5.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v4.0.1...v5.0.0) (2023-07-13)
- feat!: drop support for IE 11 (#629) ([6c49fb6](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/6c49fb6c1b1f18bbff02dbd77a37a21bdb40c959)), closes [#629](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/629)
### BREAKING CHANGES
- Remove support for IE11
Co-authored-by: texastony <5892063+texastony@users.noreply.github.com>
# [4.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v3.0.0...v4.0.0) (2023-02-20)
**Note:** Version bump only for package @aws-crypto/sha1-browser
# [3.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.2...v3.0.0) (2023-01-12)
- feat!: replace Hash implementations with Checksum interface (#492) ([da43dc0](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/da43dc0fdf669d9ebb5bfb1b1f7c79e46c4aaae1)), closes [#492](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/492)
### BREAKING CHANGES
- All classes that implemented `Hash` now implement `Checksum`.
## [2.0.2](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v2.0.1...v2.0.2) (2022-09-07)
### Bug Fixes
- **#337:** update @aws-sdk/types ([#373](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/373)) ([b26a811](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/b26a811a392f5209c7ec7e57251500d4d78f97ff)), closes [#337](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/337)
# [2.0.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.2.2...v2.0.0) (2021-10-25)
**Note:** Version bump only for package @aws-crypto/sha1-browser
# [1.2.0](https://github.com/aws/aws-sdk-js-crypto-helpers/compare/v1.1.1...v1.2.0) (2021-09-17)
### Bug Fixes
- Adding ie11-detection dependency to sha1-browser ([#213](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/213)) ([138750d](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/138750d96385b8cc479b6f54c500ee1b5380648c))
### Features
- Add SHA1 ([#208](https://github.com/aws/aws-sdk-js-crypto-helpers/issues/208)) ([45c50ff](https://github.com/aws/aws-sdk-js-crypto-helpers/commit/45c50ffa3acc9e3bf4039ab59a0102e4d40455ec))

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,21 @@
# @aws-crypto/sha1-browser
SHA1 wrapper for browsers that prefers `window.crypto.subtle`.
SHA1 is **NOT** a cryptographically secure algorithm.
It should _only_ be used for non cryptographic functions like checksums.
## Usage
```
import {Sha1} from '@aws-crypto/sha1-browser'
const hash = new Sha1();
hash.update('some data');
const result = await hash.digest();
```
## Test
`npm test`

View File

@@ -0,0 +1,10 @@
export declare const SHA_1_HASH: {
name: "SHA-1";
};
export declare const SHA_1_HMAC_ALGO: {
name: "HMAC";
hash: {
name: "SHA-1";
};
};
export declare const EMPTY_DATA_SHA_1: Uint8Array;

View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EMPTY_DATA_SHA_1 = exports.SHA_1_HMAC_ALGO = exports.SHA_1_HASH = void 0;
exports.SHA_1_HASH = { name: "SHA-1" };
exports.SHA_1_HMAC_ALGO = {
name: "HMAC",
hash: exports.SHA_1_HASH,
};
exports.EMPTY_DATA_SHA_1 = new Uint8Array([
218,
57,
163,
238,
94,
107,
75,
13,
50,
85,
191,
239,
149,
96,
24,
144,
175,
216,
7,
9,
]);
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAElD,QAAA,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,kBAAU;CACjB,CAAC;AAEW,QAAA,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}

View File

@@ -0,0 +1,8 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private hash;
constructor(secret?: SourceData);
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sha1 = void 0;
var webCryptoSha1_1 = require("./webCryptoSha1");
var supports_web_crypto_1 = require("@aws-crypto/supports-web-crypto");
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
var util_1 = require("@aws-crypto/util");
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
if ((0, supports_web_crypto_1.supportsWebCrypto)((0, util_locate_window_1.locateWindow)())) {
this.hash = new webCryptoSha1_1.Sha1(secret);
}
else {
throw new Error("SHA1 not supported");
}
}
Sha1.prototype.update = function (data, encoding) {
this.hash.update((0, util_1.convertToBuffer)(data));
};
Sha1.prototype.digest = function () {
return this.hash.digest();
};
Sha1.prototype.reset = function () {
this.hash.reset();
};
return Sha1;
}());
exports.Sha1 = Sha1;
//# sourceMappingURL=crossPlatformSha1.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"crossPlatformSha1.js","sourceRoot":"","sources":["../../src/crossPlatformSha1.ts"],"names":[],"mappings":";;;AAAA,iDAAwD;AAExD,uEAAoE;AACpE,kEAA2D;AAC3D,yCAAmD;AAEnD;IAGE,cAAY,MAAmB;QAC7B,IAAI,IAAA,uCAAiB,EAAC,IAAA,iCAAY,GAAE,CAAC,EAAE;YACrC,IAAI,CAAC,IAAI,GAAG,IAAI,oBAAa,CAAC,MAAM,CAAC,CAAC;SACvC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SACvC;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB,EAAE,QAAsC;QAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAA,sBAAe,EAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,qBAAM,GAAN;QACE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IACH,WAAC;AAAD,CAAC,AAtBD,IAsBC;AAtBY,oBAAI"}

View File

@@ -0,0 +1,2 @@
export * from "./crossPlatformSha1";
export { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebCryptoSha1 = void 0;
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./crossPlatformSha1"), exports);
var webCryptoSha1_1 = require("./webCryptoSha1");
Object.defineProperty(exports, "WebCryptoSha1", { enumerable: true, get: function () { return webCryptoSha1_1.Sha1; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;AAAA,8DAAoC;AACpC,iDAAwD;AAA/C,8GAAA,IAAI,OAAiB"}

View File

@@ -0,0 +1,2 @@
import { SourceData } from "@aws-sdk/types";
export declare function isEmptyData(data: SourceData): boolean;

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEmptyData = void 0;
function isEmptyData(data) {
if (typeof data === "string") {
return data.length === 0;
}
return data.byteLength === 0;
}
exports.isEmptyData = isEmptyData;
//# sourceMappingURL=isEmptyData.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isEmptyData.js","sourceRoot":"","sources":["../../src/isEmptyData.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAC,IAAgB;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;KAC1B;IAED,OAAO,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC;AAC/B,CAAC;AAND,kCAMC"}

View File

@@ -0,0 +1,9 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private readonly key;
private toHash;
constructor(secret?: SourceData);
update(data: SourceData): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sha1 = void 0;
var util_utf8_1 = require("@smithy/util-utf8");
var isEmptyData_1 = require("./isEmptyData");
var constants_1 = require("./constants");
var util_locate_window_1 = require("@aws-sdk/util-locate-window");
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
this.toHash = new Uint8Array(0);
if (secret !== void 0) {
this.key = new Promise(function (resolve, reject) {
(0, util_locate_window_1.locateWindow)()
.crypto.subtle.importKey("raw", convertToBuffer(secret), constants_1.SHA_1_HMAC_ALGO, false, ["sign"])
.then(resolve, reject);
});
this.key.catch(function () { });
}
}
Sha1.prototype.update = function (data) {
if ((0, isEmptyData_1.isEmptyData)(data)) {
return;
}
var update = convertToBuffer(data);
var typedArray = new Uint8Array(this.toHash.byteLength + update.byteLength);
typedArray.set(this.toHash, 0);
typedArray.set(update, this.toHash.byteLength);
this.toHash = typedArray;
};
Sha1.prototype.digest = function () {
var _this = this;
if (this.key) {
return this.key.then(function (key) {
return (0, util_locate_window_1.locateWindow)()
.crypto.subtle.sign(constants_1.SHA_1_HMAC_ALGO, key, _this.toHash)
.then(function (data) { return new Uint8Array(data); });
});
}
if ((0, isEmptyData_1.isEmptyData)(this.toHash)) {
return Promise.resolve(constants_1.EMPTY_DATA_SHA_1);
}
return Promise.resolve()
.then(function () { return (0, util_locate_window_1.locateWindow)().crypto.subtle.digest(constants_1.SHA_1_HASH, _this.toHash); })
.then(function (data) { return Promise.resolve(new Uint8Array(data)); });
};
Sha1.prototype.reset = function () {
this.toHash = new Uint8Array(0);
};
return Sha1;
}());
exports.Sha1 = Sha1;
function convertToBuffer(data) {
if (typeof data === "string") {
return (0, util_utf8_1.fromUtf8)(data);
}
if (ArrayBuffer.isView(data)) {
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
}
return new Uint8Array(data);
}
//# sourceMappingURL=webCryptoSha1.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"webCryptoSha1.js","sourceRoot":"","sources":["../../src/webCryptoSha1.ts"],"names":[],"mappings":";;;AACA,+CAA6C;AAC7C,6CAA4C;AAC5C,yCAA4E;AAC5E,kEAA2D;AAE3D;IAIE,cAAY,MAAmB;QAFvB,WAAM,GAAe,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAG7C,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE;YACrB,IAAI,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC,UAAC,OAAO,EAAE,MAAM;gBACrC,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,SAAS,CACtB,KAAK,EACL,eAAe,CAAC,MAAM,CAAC,EACvB,2BAAe,EACf,KAAK,EACL,CAAC,MAAM,CAAC,CACT;qBACA,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAO,CAAC,CAAC,CAAC;SAC1B;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB;QACrB,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,EAAE;YACrB,OAAO;SACR;QAED,IAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,IAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAC3C,CAAC;QACF,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/B,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,CAAC;IAED,qBAAM,GAAN;QAAA,iBAgBC;QAfC,IAAI,IAAI,CAAC,GAAG,EAAE;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAC,GAAG;gBACvB,OAAA,IAAA,iCAAY,GAAE;qBACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2BAAe,EAAE,GAAG,EAAE,KAAI,CAAC,MAAM,CAAC;qBACrD,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,IAAI,UAAU,CAAC,IAAI,CAAC,EAApB,CAAoB,CAAC;YAFvC,CAEuC,CACxC,CAAC;SACH;QAED,IAAI,IAAA,yBAAW,EAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,4BAAgB,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC,OAAO,EAAE;aACrB,IAAI,CAAC,cAAM,OAAA,IAAA,iCAAY,GAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAU,EAAE,KAAI,CAAC,MAAM,CAAC,EAA5D,CAA4D,CAAC;aACxE,IAAI,CAAC,UAAC,IAAI,IAAK,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAArC,CAAqC,CAAC,CAAC;IAC3D,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACH,WAAC;AAAD,CAAC,AAxDD,IAwDC;AAxDY,oBAAI;AA0DjB,SAAS,eAAe,CAAC,IAAgB;IACvC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC;KACvB;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QAC5B,OAAO,IAAI,UAAU,CACnB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAC/C,CAAC;KACH;IAED,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}

View File

@@ -0,0 +1,10 @@
export declare const SHA_1_HASH: {
name: "SHA-1";
};
export declare const SHA_1_HMAC_ALGO: {
name: "HMAC";
hash: {
name: "SHA-1";
};
};
export declare const EMPTY_DATA_SHA_1: Uint8Array;

View File

@@ -0,0 +1,28 @@
export var SHA_1_HASH = { name: "SHA-1" };
export var SHA_1_HMAC_ALGO = {
name: "HMAC",
hash: SHA_1_HASH,
};
export var EMPTY_DATA_SHA_1 = new Uint8Array([
218,
57,
163,
238,
94,
107,
75,
13,
50,
85,
191,
239,
149,
96,
24,
144,
175,
216,
7,
9,
]);
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,UAAU,GAAsB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAE/D,MAAM,CAAC,IAAM,eAAe,GAA8C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,IAAM,gBAAgB,GAAG,IAAI,UAAU,CAAC;IAC7C,GAAG;IACH,EAAE;IACF,GAAG;IACH,GAAG;IACH,EAAE;IACF,GAAG;IACH,EAAE;IACF,EAAE;IACF,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,EAAE;IACF,EAAE;IACF,GAAG;IACH,GAAG;IACH,GAAG;IACH,CAAC;IACD,CAAC;CACF,CAAC,CAAC"}

View File

@@ -0,0 +1,8 @@
import { Checksum, SourceData } from "@aws-sdk/types";
export declare class Sha1 implements Checksum {
private hash;
constructor(secret?: SourceData);
update(data: SourceData, encoding?: "utf8" | "ascii" | "latin1"): void;
digest(): Promise<Uint8Array>;
reset(): void;
}

View File

@@ -0,0 +1,26 @@
import { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";
import { supportsWebCrypto } from "@aws-crypto/supports-web-crypto";
import { locateWindow } from "@aws-sdk/util-locate-window";
import { convertToBuffer } from "@aws-crypto/util";
var Sha1 = /** @class */ (function () {
function Sha1(secret) {
if (supportsWebCrypto(locateWindow())) {
this.hash = new WebCryptoSha1(secret);
}
else {
throw new Error("SHA1 not supported");
}
}
Sha1.prototype.update = function (data, encoding) {
this.hash.update(convertToBuffer(data));
};
Sha1.prototype.digest = function () {
return this.hash.digest();
};
Sha1.prototype.reset = function () {
this.hash.reset();
};
return Sha1;
}());
export { Sha1 };
//# sourceMappingURL=crossPlatformSha1.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"crossPlatformSha1.js","sourceRoot":"","sources":["../../src/crossPlatformSha1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD;IAGE,cAAY,MAAmB;QAC7B,IAAI,iBAAiB,CAAC,YAAY,EAAE,CAAC,EAAE;YACrC,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;SACvC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SACvC;IACH,CAAC;IAED,qBAAM,GAAN,UAAO,IAAgB,EAAE,QAAsC;QAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,qBAAM,GAAN;QACE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,oBAAK,GAAL;QACE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IACH,WAAC;AAAD,CAAC,AAtBD,IAsBC"}

View File

@@ -0,0 +1,2 @@
export * from "./crossPlatformSha1";
export { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";

View File

@@ -0,0 +1,3 @@
export * from "./crossPlatformSha1";
export { Sha1 as WebCryptoSha1 } from "./webCryptoSha1";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC"}

View File

@@ -0,0 +1,2 @@
import { SourceData } from "@aws-sdk/types";
export declare function isEmptyData(data: SourceData): boolean;

View File

@@ -0,0 +1,7 @@
export function isEmptyData(data) {
if (typeof data === "string") {
return data.length === 0;
}
return data.byteLength === 0;
}
//# sourceMappingURL=isEmptyData.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isEmptyData.js","sourceRoot":"","sources":["../../src/isEmptyData.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;KAC1B;IAED,OAAO,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC;AAC/B,CAAC"}

Some files were not shown because too many files have changed in this diff Show More