💡 Повний робочий приклад доступний на GitHub:
office-metadata-pii-cleanup-nodejs
Вступ
Точка завантаження приймає DOCX від співробітника та зберігає його у заявці клієнта. Текст у порядку. Властивості — ні: у файлі вказано ім’я автора, колегу, який останнім зберіг файл, менеджера відділу з корпоративного шаблону та, оскільки файл походить з SharePoint, затверджувача, який його підписав.
Санітайзер метаданих — це невеликий скрипт, який видаляє ці властивості перед збереженням файлу, а потім перевіряє свою роботу. У цьому посібнику ми створимо такий скрипт на Node.js за допомогою GroupDocs.Metadata у чотирьох кроках: вибір властивостей за тегом, вибір за назвою, повне стирання, коли селективність перестає допомагати, і перевірка залишку. Кожен крок — кілька рядків, а готовий скрипт — менше сотні рядків.
Чому санітизація метаданих важлива
Дані накопичуються без будь‑якого вибору. Word записує Author і LastSavedBy з облікового запису операційної системи при кожному збереженні, веде лічильник ревізій, відстежує TotalEditingTime і фіксує LastPrinted. Сервери документів додають шляхи робочих процесів, ідентифікатори затверджувачів і URI типу вмісту під час реєстрації. Жодна з цих даних не відображається під час читання чи друку документа, тому їх не помічає навіть уважний редактор.
Сенс використання Node.js замість ручної обробки полягає в тому, що скрипт повертає числа: кожен виклик видалення повідомляє, скільки властивостей було видалено, і цей підрахунок можна записати в журнал, використати в тесті або прикріпити до запису, до якого належить документ.
Є ще одна причина, менш очевидна, доки не запущено пакетну задачу. Ручне очищення — це рішення, прийняте один раз для кожного файлу тим, хто його обробляє, тому двоє людей, що санітизують один і той самий тип документу, отримують різні результати. Скрипт фіксує правило в одному місці: ті самі чотири теги, ті самі списки підрядків, застосовані однаково, незалежно від того, чи обробляє черга три файли, чи три тисячі.
Передумови
Пакет працює на Node.js через Java, тому машині потрібне середовище виконання Java поряд з Node.
Встановлення
npm install @groupdocs/groupdocs.metadata
Зразковий проєкт фіксує версію 26.7 і додає запис overrides, який встановлює nan у ^2.22.0, що дозволяє будувати нативне прив’язування на поточних випусках Node. Без файлу ліцензії бібліотека працює в режимі оцінки, що достатньо для виконання всіх кроків цього посібника.
Крок 1 – Вибір властивостей за їх значенням
Назви властивостей різняться між форматами та пакетами, тому перше правило працює з тегами. ContainsTagSpecification приймає тег і підходить під будь‑яку властивість, що його містить; .or() об’єднує специфікації в одну.
const T = groupdocs.Tags;
const spec = new groupdocs.ContainsTagSpecification(T.getPerson().getCreator())
.or(new groupdocs.ContainsTagSpecification(T.getPerson().getEditor()))
.or(new groupdocs.ContainsTagSpecification(T.getPerson().getManager()))
.or(new groupdocs.ContainsTagSpecification(T.getCorporate().getCompany()));
const affected = metadata.removeProperties(spec);
metadata.save(outputPath);
Ключові моменти:
- Чотири теги охоплюють групу ідентифікації: творець, редактор, менеджер і корпоративне поле компанії.
- Title, Subject і Keywords залишаються недоторканими, тому індекс записів, який їх використовує, продовжує працювати.
removePropertiesповертає кількість змінених елементів, а не булеве значення.
Обгорніть весь код у try/finally з metadata.close() у блоці finally. Прив’язка тримає файл відкритим до цього моменту, а цикл без закриття швидко вичерпує дескриптори.
Крок 2 – Вибір властивостей за назвою
Коментарі, лічильники ревізій і серверні поля не мають тегів. Для них WithNameSpecification(needle, false) підходить під будь‑яку властивість, назва якої містить needle, а чотирирядковий будівельник створює одну специфікацію на кожний підрядок:
let spec = null;
for (const needle of needles) {
const s = new groupdocs.WithNameSpecification(needle, false /* fullMatch */);
spec = spec ? spec.or(s) : s;
}
return spec;
Три проходи повторно використовують цей будівельник з різними списками. Спочатку — коментарі:
const affected = metadata.removeProperties(
nameContainsSpec(['Comment', 'Reviewer', 'Reviewed']));
metadata.save(outputPath);
Група, що часто забувається, — це хронологія редагувань, і саме вона описує, як був створений документ:
const affected = metadata.removeProperties(nameContainsSpec([
'Revision', 'TrackedChange', 'LastPrinted', 'TotalEditingTime', 'EditTime',
]));
metadata.save(outputPath);
Прохід для SharePoint — той самий виклик, лише з Server, Workflow, Approver, ContentType і Template. Підрядкове порівняння навмисне: воно ловить CommentsCount разом із Comment, не вимагаючи точного списку імен для кожного формату.
Крок 3 – Стерти все, коли селективність перестає допомагати
Для копії, що залишає організацію, один виклик замінює чотири проходи:
const affected = metadata.sanitize();
metadata.save(outputPath);
sanitize() очищає всі пакети метаданих, які виявляє бібліотека, включаючи користувацькі частини OOXML, і його підрахунок зазвичай перевищує суму підрахунків цільових проходів. Він також видаляє Title і Subject, тому його слід застосовувати на межі, а не в циклі перевірки.
Крок 4 – Перевірка, бо тихий пропуск виглядає як успіх
Сканування повторно використовує ті ж специфікації через findProperties, який лише читає. Результат — колекція Java, тому її обходять за індексом:
const props = metadata.findProperties(tagSpec.or(nameSpec));
for (let i = 0; i < props.getCount(); i++) {
const p = props.get_Item(i);
const val = p.getValue && p.getValue();
const value = val ? String(val.getRawValue ? val.getRawValue() : val) : '';
if (!value || value === '0' || value === '0.0') continue;
leaks.push(`${p.getName()}=${value}`);
}
Фільтр порожніх і нульових значень виправданий. Я додав його після того, як один запуск провалився через лічильник ревізій, який був скинутий до 0, і сканер правдиво повідомив про залишкову властивість.
Повний робочий приклад
Репозиторій з’єднує шість функцій у index.js, який застосовує ліцензію, запускає кожен прохід над resources/pii-sample.docx, перевіряє, що кожен вихідний файл існує, і завершує перевіркою, що список витоків порожній. Невдала перевірка завершує процес з ненульовим кодом, тому весь скрипт працює як перевірка в CI, а не як демонстрація для читання.
Один нюанс варто скопіювати у свою версію: кожен прохід читає один і той самий вихідний файл і записує окремий результат, а не передає очищений файл у наступний прохід. Це зберігає незалежність підрахунків, тому рядок журналу для проходу коментарів показує, що знайшло правило коментарів, а не те, що залишилося після правила ідентифікації.
Коли слід запускати цільовий прохід замість sanitize()?
Коли документ ще використовується. Файли, що циркулюють між рецензентами, покладаються на Title, Subject і Keywords для пошуку та класифікації, а sanitize() видаляє всі три разом із персональними даними. Запускайте проходи ідентифікації та коментарів під час спільної роботи, залишаючи описові поля недоторканими, а повне стирання залишайте для копії, що залишає організацію.
Реальні сценарії використання
Обробник завантаження
Маршрут Express санітизує вкладення перед записом у сховище, реєструє підрахунок змінених властивостей у заявці та відхиляє завантаження, якщо список витоків не порожній.
Нічна задача експорту
Працівник обходить папку експорту, застосовує проходи ідентифікації та серверні, і завершує задачу помилкою замість попередження, якщо документ все ще містить залишкові PII.
Ворота перед публікацією
Крок збірки санітизує прикріплені документи перед випуском, використовуючи sanitize(), бо в цих файлах не потрібно зберігати їх метадані.
Кращі практики та поради
- Завжди записуйте у новий шлях, щоб оригінал залишався для вирішення спорів.
- Закривайте об’єкт метаданих у блоці
finally, особливо в циклах. - Об’єднуйте специфікації за допомогою
.or()у пакетних задачах; один відкритий і один збережений краще, ніж чотири. - Логуйте підрахунок змінених елементів за кожний прохід, включаючи нулі, щоб було видно, коли формат не розпізнано.
Устранення поширених проблем
Підрахунок змінених елементів дорівнює нулю, хоча документ явно «брудний»
Перевірте, чи вхідний формат розпізнається, перш ніж робити висновок, що файл чистий; нечитаємий файл і чистий файл дають однаковий нульовий результат.
Перевірка витоків повідомляє про властивості, які ви щойно видалили
Скануйте збережений вихідний шлях, а не вхідний. Сканер читає той файл, який йому передано.
Бульбашки коментарів все ще видно у Word
Текст коментаря зберігається в тілі документа, а не в пакеті метаданих. GroupDocs.Metadata очищає лише властивості, пов’язані з коментарями; для видалення самих бульбашок потрібна бібліотека редагування вмісту, наприклад Aspose.Words.
Висновок
Чотири кроки, шість функцій, один скрипт, який повідомляє, що він зробив. Тег‑специфікації охоплюють групу ідентифікації у всіх форматах, специфікації за назвою охоплюють сімейства, які не класифікуються тегами, sanitize() обробляє межу, а сканування витоків перетворює все це на перевірку. Клонуйте репозиторій, запустіть його над документом, який пройшов реальний раунд рецензування, і подивіться на підрахунки, перш ніж вирішувати, які проходи потрібні вашому конвеєру.