init
This commit is contained in:
commit
9e617a6f1f
45
README.md
Normal file
45
README.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Nextcloud Passwords to Bitwarden
|
||||
|
||||
This project allows you to convert Nextcloud Passwords CSV to a Bitwarden JSON file.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
git clone https://gitnet.fr/deblan/nextcloud_passwords_to_bitwarden
|
||||
composer install
|
||||
```
|
||||
|
||||
## How to
|
||||
|
||||
### On Nextcloud
|
||||
|
||||
* Go to "Personal settings"
|
||||
* Set "English (US)" as language
|
||||
* Go to "Passwords"
|
||||
* Click on "More"
|
||||
* Click on "Backup and restore"
|
||||
* Choose "Backup or export"
|
||||
* Choose "Predefined CSV"
|
||||
* Check "Export Passwords" and "Export Folders"
|
||||
* Click on "Export"
|
||||
* Unzip the download file
|
||||
|
||||
### On the project
|
||||
|
||||
```
|
||||
php index.php /path/to/Folders.csv /path/to/Passwords.csv > bitwarden_passwords.json
|
||||
```
|
||||
|
||||
### On Bitwarden/Vaultwarden
|
||||
|
||||
* Go to tools
|
||||
* Go to "Import data"
|
||||
* Choose "Bitwarden (json)" as file format
|
||||
* Choose the file "bitwarden_passwords.json"
|
||||
* Click on "Import data"
|
||||
|
||||
### Clean up datas
|
||||
|
||||
* Remove the downloaded archive
|
||||
* Remove extracted files
|
||||
* Remove bitwarden_passwords.json
|
5
composer.json
Normal file
5
composer.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"require": {
|
||||
"league/csv": "^9.15"
|
||||
}
|
||||
}
|
121
index.php
Normal file
121
index.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
use League\Csv\Reader;
|
||||
|
||||
function getRecords(string $file): Iterator
|
||||
{
|
||||
$csv = Reader::createFromPath($file, 'r');
|
||||
$csv->setHeaderOffset(0);
|
||||
|
||||
return $csv->getRecords();
|
||||
}
|
||||
|
||||
function usage(int $exitCode = 0, ?string $error = null): void
|
||||
{
|
||||
$usage = [];
|
||||
|
||||
if (null !== $error) {
|
||||
$usage[] = $error;
|
||||
$usage[] = '';
|
||||
}
|
||||
|
||||
$file = __FILE__;
|
||||
|
||||
$usage[] = 'Usage';
|
||||
$usage[] = " php {$file} -h|--help";
|
||||
$usage[] = " php {$file} /path/to/Folders.csv /path/to/Passwords.csv";
|
||||
|
||||
file_put_contents('php://stderr', implode("\n", $usage));
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
function checkFile(?string $file): void
|
||||
{
|
||||
if (null === $file) {
|
||||
usage(1, 'File not defined');
|
||||
}
|
||||
|
||||
if (!is_file($file) || !is_readable($file)) {
|
||||
usage(1, 'File not found or not readable: '.$file);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($argv as $value) {
|
||||
if (in_array($value, ['-h', '--help'])) {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
$folders = $argv[1] ?? null;
|
||||
$passwords = $argv[2] ?? null;
|
||||
|
||||
checkFile($folders);
|
||||
checkFile($passwords);
|
||||
|
||||
$datas = [
|
||||
'encrypted' => false,
|
||||
'folders' => [],
|
||||
'items' => [],
|
||||
];
|
||||
|
||||
foreach (getRecords($folders) as $item) {
|
||||
$datas['folders'][] = [
|
||||
'id' => $item['Id'],
|
||||
'name' => $item['Label'],
|
||||
];
|
||||
}
|
||||
|
||||
foreach (getRecords($passwords) as $item) {
|
||||
$fields = [];
|
||||
|
||||
if (!empty($item['Custom Fields'])) {
|
||||
$elements = explode("\n", trim($item['Custom Fields']));
|
||||
|
||||
if (!empty($elements)) {
|
||||
foreach ($elements as $element) {
|
||||
preg_match('/^(.*), (.*): (.*)$/iU', $element, $match);
|
||||
|
||||
$fields[] = [
|
||||
'name' => $match[1],
|
||||
'value' => $match[3],
|
||||
'linkedId' => null,
|
||||
'type' => match ($match[2]) {
|
||||
'secret' => 1,
|
||||
default => 0,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$datas['items'][] = [
|
||||
'passwordHistory' => null,
|
||||
'revisionDate' => null,
|
||||
'creationDate' => null,
|
||||
'deletedDate' => null,
|
||||
'id' => $item['Id'],
|
||||
'organizationId' => null,
|
||||
'folderId' => $item['Folder Id'],
|
||||
'type' => 1,
|
||||
'reprompt' => 0,
|
||||
'name' => $item['Label'],
|
||||
'notes' => $item['Notes'],
|
||||
'favorite' => 'true' === $item['Favorite'],
|
||||
'fields' => $fields,
|
||||
'login' => [
|
||||
'fido2Credentials' => [],
|
||||
'uris' => [[
|
||||
'match' => null,
|
||||
'uri' => $item['Url'],
|
||||
]],
|
||||
'username' => $item['Username'],
|
||||
'password' => $item['Password'],
|
||||
'topt' => null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($datas);
|
Loading…
Reference in a new issue