Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pass_import/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

import os
from typing import Dict
from typing import Dict, List
from abc import abstractmethod

from pass_import import clean
Expand Down Expand Up @@ -46,7 +46,7 @@ class PasswordManager(Asset):
def __init__(self, prefix=None, settings=None):
settings = {} if settings is None else settings

self.data: Dict[str, str] = []
self.data: List[Dict[str, str]] = []
self.root = settings.get('root', '')
self.cols = settings.get('cols', '')
self.action = settings.get('action', Cap.IMPORT)
Expand Down
45 changes: 45 additions & 0 deletions pass_import/managers/synology.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
# -*- encoding: utf-8 -*-
# pass import - Passwords importer swiss army knife
# Copyright (C) 2024 SAY-5 <say.apm35@gmail.com>.
# Copyright (C) 2026 Ahmad Othman <ahmad.ali.othman@outlook.com>.
#

from pass_import.errors import FormatError
import json
from typing import TypedDict
from pass_import.core import register_managers
from pass_import.formats.csv import CSV


class CustomAutofillField(TypedDict):
Type: str
AutofillWeb_Title: str
AutofillWeb_Type: str
AutofillWeb: str
AutofillWeb_Selector: str


class CustomTextField(TypedDict):
Type: str
Text_Title: str
Text: str


class SynologyC2CSV(CSV):
"""Importer for Synology C2 Password in CSV format."""
name = 'synology'
Expand All @@ -23,5 +41,32 @@ class SynologyC2CSV(CSV):
'comments': 'Notes'
}

def parse(self):
"""Parse C2 Password CSV file, handling custom fields in Others column."""
super().parse()
for entry in self.data:
entry.pop("Login_URL_Match_Rules", None)
entry.pop("Tag", None)
entry.pop("Tag_Color", None)
entry.pop("Favorite", None)

raw = entry.pop("Others", "")
if raw and raw.strip():
try:
others = json.loads(raw)
if "Custom" in others:
custom = others.get("Custom")
if isinstance(custom, list):
for item in custom:
if item["Type"] == "Text":
field: CustomTextField = item
entry[field["Text_Title"].title()] = field["Text"]
elif item["Type"] == "AutofillWeb":
field: CustomAutofillField = item
entry[field["AutofillWeb_Title"].title()] = field["AutofillWeb"]

except json.JSONDecodeError as e:
raise FormatError(f"Invalid JSON in 'Others' column: {e}")


register_managers(SynologyC2CSV)
2 changes: 2 additions & 0 deletions tests/assets/db/c2password-malformed.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Display_Name,Login_Username,Login_Password,Login_URLs,Login_TOTP,Login_URL_Match_Rules,Notes,Tag,Tag_Color,Favorite,Others
broken,user,pass,https://x.com,,tld-plus-one,,,,,"not valid json at all"
234 changes: 234 additions & 0 deletions tests/assets/db/c2password.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
Login_URLs,Login_URL_Match_Rules,Login_Username,Login_Password,Login_TOTP,Display_Name,Tag,Tag_Color,Favorite,Notes,Others
https://obsidian.md/account/,tld-plus-one,claudia22@example.com,zVhw534B6HQy,,obsidian.md,,,,,
https://client.googiehost.com/cart.php?a=checkout&e=false,tld-plus-one,vsmith@example.com,Mci^A7*gUw6qMp,,client.googiehost.com,,,,,
https://github.com,tld-plus-one,MichaelWhite,9rXQ4Xyl^7,otpauth://totp/GitHub:MichaelWhite?secret=9CZBZAOFRM&issuer=GitHub,github.com,,,,,
https://en.wikipedia.org/w/index.php,tld-plus-one,HollyHowell,#x5JMrV^7+,,wikipedia.org,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Confirm password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": ""#x5JMrV^7+"",
""AutofillWeb_Selector"": ""#wpRetype""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Email address (recommended)"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""vsmith@example.com"",
""AutofillWeb_Selector"": ""#wpEmail""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""CAPTCHA Security check"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""deathdonna"",
""AutofillWeb_Selector"": ""#mw-input-captchaWord""
}
]
}"
https://my.anydesk.com/auth/realms/myanydesk/protocol/openid-connect/auth?client_id=myanydesk-frontend&code_challenge=G380ldjh0ubWB6JBYdgyw8uoLyzcIiVrP8ROOBdyin0ZT&code_challenge_method=S256&kc_idp_hint=custom-idp&redirect_uri=https%3A%2F%2Fmy.anydesk.com%2Fv2%2F&response_mode=fragment&response_type=code&scope=openid&state=c27cd912-3334-465e-91be-71ba776eea64&ui_locales=en,tld-plus-one,vsmith@example.com,RAYb0h4idYOCLpL2,,my.anydesk.com,,,,,
android://iQcLnIDl0CGP7IFOyNzMVJOH-vdIhdpXQeivuFwnPTwzZxhGNycafCfQkV8AqCwwNnMKdE3Yb9upiC2MlkcDfA==@com.facebook.katana/,tld-plus-one,01234567890,$ri3sPuLw4,,android://iQcLnIDl0CGP7IFOyNzMVJOH-vdIhdpXQeivuFwnPTwzZxhGNycafCfQkV8AqCwwNnMKdE3Yb9upiC2MlkcDfA==@com.facebook.katana/,,,,,
https://codeforces.com/register,tld-plus-one,claudia22@example.com,&x35h@Fz6I,,codeforces.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Text"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""JohnLucero"",
""AutofillWeb_Selector"": ""[name=\""handle\""]""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": ""&x35h@Fz6I"",
""AutofillWeb_Selector"": ""[name=\""passwordConfirmation\""]""
}
]
}"
https://account.proton.me/pass/signup,tld-plus-one,claudia22@example.com,)5R+Tw)Nx8,,proton.me,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": "")5R+Tw)Nx8"",
""AutofillWeb_Selector"": ""#password""
}
]
}"
https://phpmyadmin.freedb.tech,tld-plus-one,freedb_John,M!JPQbyJ@4,,https://phpmyadmin.freedb.tech,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Server:"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""sql.freedb.tech"",
""AutofillWeb_Selector"": ""#serverNameInput""
}
]
}"
https://scribehow.com/signup,tld-plus-one,vsmith@example.com,2_2I8EnO67,,scribehow.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Full name"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Heather Costa"",
""AutofillWeb_Selector"": ""#name""
}
]
}"
https://www.tybaa.com,tld-plus-one,محمد_عبد_الشكور,$)_nAMxh!9,,tybaa.com,,,,,
archlinux.org,tld-plus-one,SusanGillespie,*G3#HVArU!,,archlinux.org,,,,,"{
""Custom"": [
{
""Type"": ""Text"",
""Text_Title"": ""Email"",
""Text"": ""claudia22@example.com""
}
]
}"
https://x.com/i/flow/password_reset,tld-plus-one,,g^k_9J7oKT,,x.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Enter a new password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": ""g^k_9J7oKT"",
""AutofillWeb_Selector"": "".css-175oi2r:nth-child(1) > .css-175oi2r > .css-146c3p1 > [name=\""password\""]""
}
]
}"
http://127.0.0.1:65000/web/register,tld-plus-one,claudia22@example.com,"Qae.=`0z''hG*FK{4W!8:s,G""",,127.0.0.1:65000,,,,,
https://account.postmarkapp.com/sign_up,tld-plus-one,vsmith@example.com,^lBb)!&dA9,,account.postmarkapp.com,,,,,
https://app.clickup.com/,tld-plus-one,claudia22@example.com,da2eTfLqB%,,clickup.com,,,,,"{
""Login_Autosave_Web_Anti_Selectors"": [
""#password-input""
]
}"
"https://auth0.openai.com
https://chatgpt.com","tld-plus-one
tld-plus-one",claudia22@example.com,=#FhcshvymJ6Dc5,otpauth://totp/OpenAI%3Aqmorrison%40example.org?secret=Z7oWE5HLuWARlRQ4p5ABkN8M86iNcwIC&issuer=OpenAI,auth0.openai.com,,,,,
https://windscribe.com/signup,tld-plus-one,Cindy_Johnson,T!JUAWjg(7,,windscribe.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Email (Optional)"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""iramirez@example.com"",
""AutofillWeb_Selector"": ""#signup_email""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Enter Captcha"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""X6cmY"",
""AutofillWeb_Selector"": ""#captcha1""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Choose Password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": ""pUZ(4Xhzl9"",
""AutofillWeb_Selector"": ""#pass1""
}
]
}"
https://ollama.com/signup,tld-plus-one,Glenda_Brewer,)Kxb5!Vp85,,ollama.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Email address"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""claudia22@example.com"",
""AutofillWeb_Selector"": ""#email""
}
]
}"
https://www.freelancer.com/signup,tld-plus-one,claudia22@example.com,N%*8Ww(OIN,,freelancer.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""First Name"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""John"",
""AutofillWeb_Selector"": "".ng-tns-c2763164415-4 .NativeElement""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Last Name"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Doe"",
""AutofillWeb_Selector"": "".ng-tns-c2763164415-5 .NativeElement""
}
]
}"
https://www.nassna.com/app/Identity/Account/Login,tld-plus-one,qwilson@example.net,80EMDga7(x,,nassna.com,,,,,"{
""Custom"": [
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Remember me?"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""✓"",
""AutofillWeb_Selector"": ""#Input_RememberMe""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Phone"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""01234567890"",
""AutofillWeb_Selector"": ""#Input_PhoneNumber""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Confirm Password"",
""AutofillWeb_Type"": ""password"",
""AutofillWeb"": ""+Js#evql+8"",
""AutofillWeb_Selector"": ""#Input_ConfirmPassword""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""First Name"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Kelsey"",
""AutofillWeb_Selector"": ""#Input_FirstName""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Last Name"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Marks"",
""AutofillWeb_Selector"": ""#Input_LastName""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""City"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Paris"",
""AutofillWeb_Selector"": ""#Input_City""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Country"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""FR"",
""AutofillWeb_Selector"": ""#Input_Country""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Gender"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""M"",
""AutofillWeb_Selector"": ""#Input_gender""
},
{
""Type"": ""AutofillWeb"",
""AutofillWeb_Title"": ""Address"",
""AutofillWeb_Type"": ""text"",
""AutofillWeb"": ""Unit 7429 Box 0349 DPO AE 45359"",
""AutofillWeb_Selector"": ""#Input_Address1""
}
]
}"
Loading
Loading