Устарело
...
Администрирование
Работа с API
Импорт из Bitwarden
10 мин
пассворк поддерживает импорт паролей из файла bitwarden с помощью api запустите скрипт import js и следуйте инструкциям totp коды должны быть верные, иначе скрипт завершится с ошибкой настройка и запуск (deb архитектура) получить права root и обновить локальную базу данных пакетов sudo i apt get update установить node js и npm apt install nodejs npm y для успешного импорта версия node js должна быть выше 16 проверка установленной версии node v установка модулей для импорта npm install dotenv readline fs util passwork js создать файл импорта import js исходный код import js require("util") inspect defaultoptions depth = null; const env = require('dotenv') config() parsed; const readline = require('readline'); const fs = require('fs'); const passwork = require(' /node modules/passwork js/src/passwork api'); / @type passworkapi / const passwork = new passwork(env host); function throwfatalerror(message, error) { console error(message); console error(error); process exit(0); } (async () => { try { const \[argfilename, argcollections, argpath] = process argv slice(2); let jsonfilename; let jsondata; let collectionstoimport = \[]; let importvault; // authorize try { await passwork login(env api key, env user master pass); } catch (e) { throwfatalerror('не удалось авторизоваться', e); } const rl = readline createinterface({ input process stdin, output process stdout }); // read json from bitwarden const answerfilename = await new promise(resolve => { rl question('\nукажите файл для экспорта\n', resolve) }); jsonfilename = answerfilename ? answerfilename argfilename; try { jsondata = json parse(fs readfilesync(jsonfilename)); if (!jsondata || !jsondata hasownproperty('items')) { throw 'неверный формат json файл'; } } catch (e) { throwfatalerror('не удалось прочитать json файл', e); } // specify collections to import const answercollections = await new promise(resolve => { rl question('\nукажите через запятую id или название коллекций для экспорта (необязательно)\n', resolve) }); let collections = answercollections ? answercollections argcollections; if (collections) { collections = collections split(',') map(c => c trim()) filter((c) => c); } else { collections = \[]; } if (jsondata collections && jsondata collections length) { if (collections length === 0) { collectionstoimport = jsondata collections; } else { jsondata collections foreach(c => { if (collections includes(c name) || collections includes(c id)) { collectionstoimport push(c); } }); } } else { collectionstoimport = \[]; } collectionstoimport = \[ new set(collectionstoimport)]; // specify vault id for import const answerpath = await new promise(resolve => { rl question('\nукажите id сейфа для импорта (необязательно) \n', resolve) }); let path = answerpath ? answerpath argpath; if (path) { importvault = await passwork getvault(path); if (!importvault) { throwfatalerror('указанный для импорта сейф не найден'); } } // confirm import let confirmmessage = '\nбудут экспортированы следующие коллекции \n'; if (jsondata collections) { collectionstoimport foreach(c => { confirmmessage += `${c name} (${c id})\n`; }); } else { confirmmessage += 'личный сейф\n'; } if (importvault) { confirmmessage += `\nэкспорт будет произведен в "${importvault name}"\n`; } confirmmessage += 'продолжить? y/n\n'; const answerconfirm = await new promise(resolve => { rl question(confirmmessage, resolve) }); if (answerconfirm tolowercase() === 'y') { rl close(); importpasswords() then(() => process exit(0)) catch((e) => { throwfatalerror('error', e); }); } else { console log('операция отменена'); process exit(0); } async function importpasswords() { const logfilename = 'import ' + new date() gettime() + ' log'; function logmessage(message) { let msg = new date() toisostring() + ' ' + message + '\n'; fs appendfilesync(logfilename, msg); console log(msg); } function preparepasswordfields(data, directories) { const vaultsnames = getdirectoriesnames(directories); if (data type !== 1 && data type !== 2) { logmessage(`объект типа ${data type}, ${data name}` \+ ` из коллекций ${vaultsnames} не был импортирован`); return; } const fields = { password '', name data name, description data notes, custom \[], }; if (directories length > 1) { fields description = fields description ? (fields description + '\n') ''; fields description += `копия пароля находится в ${vaultsnames}`; } if (data login) { if (data login username) { fields login = data login username; } if (data login password) { fields password = data login password; } if (data login totp) { fields custom push({ name 'totp', value data login totp, type 'totp' }); } if (data login uris) { fields url = data login uris length === 1 ? data login uris\[0] uri data login uris reduce((a, b) => (a uri || a) + ", " + b uri, '') } } if (data fields) { data fields foreach((field) => { if (field type === 0 || field type === 2) { fields custom push({ name string(field name), value string(field value), type 'text' }); } else if (field type === 1) { fields custom push({ name string(field name), value string(field value), type 'password' }); } else { logmessage(`поле типа "link" объекта ${data name}` \+ ` из коллекций ${vaultsnames} не было импортирован`); } }); } return fields; } function getdirectories(passwordcollectionids, collections) { const directories = \[]; for (const collectionid of passwordcollectionids) { if (collections hasownproperty(collectionid)) { directories push(collections\[collectionid]); } } return directories; } function getdirectoriesnames(directories) { return directories length > 1 ? directories reduce((a, b) => (a name || a) + ", " + b name) directories\[0] name; } logmessage('импорт из файла ' + jsonfilename); if (collectionstoimport length) { if (importvault) { // collections as folders const folders = {}; for (let c = 0; c < collectionstoimport length; c++) { const item = collectionstoimport\[c]; folders\[item id] = await passwork addfolder(importvault id, item name); logmessage(`создана папка ${folders\[item id] name} на основе коллекции ${item id}`) } for (let p = 0; p < jsondata items length; p++) { const passworddata = jsondata items\[p]; const folderslist = getdirectories(passworddata collectionids, folders); if (folderslist length === 0) { continue; } logmessage(`начат импорт ${passworddata name}`); let fields = preparepasswordfields(passworddata, folderslist); if (!fields) { continue; } fields vaultid = importvault id; for (const folder of folderslist) { fields folderid = folder id; await passwork addpassword(object assign({}, fields)); logmessage(`завершен импорт ${passworddata name}`); } } } else { // collections as vaults const vaults = \[]; for (let c = 0; c < collectionstoimport length; c++) { const item = collectionstoimport\[c]; const vaultid = await passwork addvault(item name); vaults\[item id] = await passwork getvault(vaultid); logmessage(`создан сейф ${vaults\[item id] name} на основе коллекции ${item id}`) } for (let p = 0; p < jsondata items length; p++) { const passworddata = jsondata items\[p]; const vaultslist = getdirectories(passworddata collectionids, vaults); if (vaultslist length === 0) { continue; } logmessage(`начат импорт ${passworddata name}`); let fields = preparepasswordfields(passworddata, vaultslist); if (!fields) { continue; } for (const vault of vaultslist) { fields vaultid = vault id; await passwork addpassword(object assign({}, fields)); logmessage(`завершен импорт ${passworddata name}`); } } } logmessage(`импорт завершен`); process exit(0); return; } if (collectionstoimport length === 0 && jsondata items\[0] organizationid === null) { // private vault import if (!importvault) { const vaultid = await passwork addvault('личный сейф', true); importvault = await passwork getvault(vaultid); logmessage(`сейф ${importvault name} был создан `); } const folders = {}; if (jsondata folders) { for (const folder of jsondata folders) { folders\[folder id] = await passwork addfolder(importvault id, folder name); } } for (let p = 0; p < jsondata items length; p++) { const passworddata = jsondata items\[p]; logmessage(`начат импорт ${passworddata name}`); let fields = preparepasswordfields(passworddata, \[importvault]); if (!fields) { continue; } fields vaultid = importvault id; if (passworddata folderid) { fields folderid = folders\[passworddata folderid] id; } await passwork addpassword(object assign({}, fields)); logmessage(`импорт завершен ${passworddata name}`); } logmessage(`импорт завершен`); process exit(0); return; } logmessage(`не удалось определить формат импорта`); process exit(0); } } catch (e) { throwfatalerror('error', e); } })(); создать файл env и указать хост пассворка, api ключ пользователя и его мастер пароль host='https //your host/api/v4' api key= user master pass= загрузить xml файл bitwarden и запустить скрипт скрипт запросит название файла node import js также эти параметры можно передать аргументами node import js bitwarden export org json "collection 1"