diff --git a/native_bridge/win/pwvault_gw.sln b/native_bridge/win/pwvault_gw.sln new file mode 100644 index 0000000..190f693 --- /dev/null +++ b/native_bridge/win/pwvault_gw.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pwvault_gw", "pwvault_gw\pwvault_gw.vcxproj", "{D3DEA12A-3254-480E-9D90-5A75813C1754}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "pwvault_gw_installer", "pwvault_gw_installer\pwvault_gw_installer.wixproj", "{F81FC781-70D9-426B-B381-44A976B37BC6}" + ProjectSection(ProjectDependencies) = postProject + {D3DEA12A-3254-480E-9D90-5A75813C1754} = {D3DEA12A-3254-480E-9D90-5A75813C1754} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Debug|x64.ActiveCfg = Debug|x64 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Debug|x64.Build.0 = Debug|x64 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Debug|x86.ActiveCfg = Debug|Win32 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Debug|x86.Build.0 = Debug|Win32 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Release|x64.ActiveCfg = Release|x64 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Release|x64.Build.0 = Release|x64 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Release|x86.ActiveCfg = Release|Win32 + {D3DEA12A-3254-480E-9D90-5A75813C1754}.Release|x86.Build.0 = Release|Win32 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Debug|x64.ActiveCfg = Debug|x86 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Debug|x86.ActiveCfg = Debug|x86 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Debug|x86.Build.0 = Debug|x86 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Release|x64.ActiveCfg = Release|x64 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Release|x64.Build.0 = Release|x64 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Release|x86.ActiveCfg = Release|x86 + {F81FC781-70D9-426B-B381-44A976B37BC6}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native_bridge/win/pwvault_gw/jsmn.cpp b/native_bridge/win/pwvault_gw/jsmn.cpp new file mode 100644 index 0000000..b4086bb --- /dev/null +++ b/native_bridge/win/pwvault_gw/jsmn.cpp @@ -0,0 +1,336 @@ +#include "jsmn.h" +/* https://github.com/zserge/jsmn + +Copyright (c) 2010 Serge A. Zaitsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +/** +* Allocates a fresh unused token from the token pull. +*/ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** +* Fills token type and boundaries. +*/ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** +* Fills next available token with JSON primitive. +*/ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t': case '\r': case '\n': case ' ': + case ',': case ']': case '}': + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** +* Fills next token with JSON string. +*/ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/': case '\\': case 'b': + case 'f': case 'r': case 'n': case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** +* Parse JSON string and fill tokens. +*/ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if (token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t': case '\r': case '\n': case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 't': case 'f': case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** +* Creates a new parser based over a given buffer with an array of tokens +* available. +*/ +void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} diff --git a/native_bridge/win/pwvault_gw/jsmn.h b/native_bridge/win/pwvault_gw/jsmn.h new file mode 100644 index 0000000..33934cd --- /dev/null +++ b/native_bridge/win/pwvault_gw/jsmn.h @@ -0,0 +1,76 @@ +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ + typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 + } jsmntype_t; + + enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 + }; + + /** + * JSON token description. + * type type (object, array, string etc.) + * start start position in JSON data string + * end end position in JSON data string + */ + typedef struct { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif + } jsmntok_t; + + /** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string + */ + typedef struct { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ + } jsmn_parser; + + /** + * Create JSON parser over an array of tokens + */ + void jsmn_init(jsmn_parser *parser); + + /** + * Run JSON parser. It parses a JSON data string into and array of tokens, each describing + * a single JSON object. + */ + int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); + +#ifdef __cplusplus +} +#endif + +#endif /* __JSMN_H_ */ \ No newline at end of file diff --git a/native_bridge/win/pwvault_gw/pwvault_gw.cpp b/native_bridge/win/pwvault_gw/pwvault_gw.cpp new file mode 100644 index 0000000..0dc2d3a --- /dev/null +++ b/native_bridge/win/pwvault_gw/pwvault_gw.cpp @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jsmn.h" + +using namespace std; + +void set_binary_io() +{ + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); +} + +wchar_t const target[] = L"masterpassword-for-firefox"; +wchar_t const password[] = L"Password"; + +wstring utf8_to_wstring(const string & s) { + UINT cp = CP_UTF8; + DWORD flags = 0; + auto sz = MultiByteToWideChar(cp, flags, s.c_str(), (int)s.size(), nullptr, 0); + if (!sz) { + throw string("Convert UTF8 to wide failed"); + } + auto * dst = new wchar_t[sz * sizeof(wchar_t)]; + auto sz2 = MultiByteToWideChar(cp, flags, s.c_str(), (int)s.size(), dst, sz); + if (sz2 != sz) + throw string("Convert UTF8 to wide failed 2"); + + auto ret = wstring(dst, dst + sz); + delete[] dst; + return ret; +} + +string wstring_to_utf8(const wstring & s) { + UINT cp = CP_UTF8; + DWORD flags = 0; + auto sz = WideCharToMultiByte(cp, flags, s.c_str(), (int)s.size(), nullptr, 0, nullptr, nullptr); + if (!sz) { + throw string("Convertion to UTF8 failed"); + } + auto * buf = new char[sz]; + auto sz2 = WideCharToMultiByte(cp, flags, s.c_str(), (int)s.size(), buf, sz, nullptr, nullptr); + if (sz2 != sz) + throw string("Convertion to UTF8 failed 2"); + + auto ret = string(buf, buf + sz); + delete[] buf; + return ret; +} + +void password_set(const wstring & s) { + CREDENTIALW credsToAdd = {}; + credsToAdd.Flags = 0; + credsToAdd.Type = CRED_TYPE_GENERIC; + credsToAdd.TargetName = const_cast(target); + credsToAdd.CredentialBlob = (LPBYTE)s.c_str(); + credsToAdd.CredentialBlobSize = (DWORD)(s.size()*sizeof(wchar_t)); + credsToAdd.Persist = CRED_PERSIST_LOCAL_MACHINE; + credsToAdd.UserName = L"masterkey"; + + if (!CredWrite(&credsToAdd, 0)) { + throw string("CredWrite failed"); + } +} + +auto password_get() { + PCREDENTIALW creds; + if (!CredRead(target, 1, 0, &creds)) { + throw string("CredRead failed"); + } + auto const * const passwordOut = (wchar_t const * const)creds->CredentialBlob; + auto ret = wstring(passwordOut, passwordOut + creds->CredentialBlobSize / sizeof(wchar_t)); + CredFree(creds); + return ret; +} + +int jsoneq(const char *json, jsmntok_t *tok, const char *s) { + if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} + +void native_bridge() { + while (1) { + jsmn_parser p; + jsmntok_t t[128]; + uint32_t msg_sz; + cin.read((char*)&msg_sz, sizeof msg_sz); + if (msg_sz > 1024) + throw 0; + if (cin.eof()) + return; + + char * buf = new char[msg_sz]; + cin.read(buf, msg_sz); + jsmn_init(&p); + + int r = jsmn_parse(&p, buf, msg_sz, t, (unsigned)size(t)); + if (r < 0) { + cerr << "Failed to parse JSON: " << r << ' ' << msg_sz << endl; + throw 0; + } + else if (r < 1 || t[0].type != JSMN_OBJECT) { + cerr << "JSON: expected object" << r << endl; + throw 0; + } + + string type; + string value; + for (auto i = 1; i < r; ++i) { + if (jsoneq(buf, &t[i], "type") == 0) { + char * pp = buf + t[i + 1].start; + type = string(pp, pp + t[i + 1].end - t[i + 1].start); + i++; + } + else if (jsoneq(buf, &t[i], "value") == 0) { + char * pp = buf + t[i + 1].start; + value = string(pp, pp + t[i + 1].end - t[i + 1].start); + i++; + } + } + if (type == string("pwget")) { + cerr << "GET PASSWORD\n"; + string s("{\"type\": \"pwgetreply\", \"success\": true, \"value\": \""); + wstring pw = password_get(); + string pwc = wstring_to_utf8(pw); + + s += wstring_to_utf8(pw) + "\"}"; + + uint32_t sz = (uint32_t)s.size(); + cout.write((char*)&sz, sizeof sz); + cout.write(s.c_str(), sz); + } + else if (type == string("pwset") && !value.empty()) { + password_set(utf8_to_wstring(value)); + string s("{\"type\": \"pwsetreply\", \"success\": true}"); + uint32_t sz = (uint32_t)s.size(); + cout.write((char*)&sz, sizeof sz); + cout.write(s.c_str(), sz); + } + else + throw string("Illegal message"); + } +} + +std::wstring ReplaceAll(const std::wstring & str, const std::wstring& from, const std::wstring& to) { + wstring ret(str); + size_t start_pos = 0; + while ((start_pos = ret.find(from, start_pos)) != std::string::npos) { + ret.replace(start_pos, from.length(), to); + start_pos += to.length(); // Handles case where 'to' is a substring of 'from' + } + return ret; +} + +wstring GetFormattedMessage(LONG errCode) +{ + LPWSTR pBuffer = NULL; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + errCode, + 0, + (LPWSTR)&pBuffer, + 0, + NULL); + + wstring ret(pBuffer); + LocalFree(pBuffer); + + return ret; +} + +HKEY createOrOpenRegKey(bool installAllUsers, const wchar_t * path) { + HKEY keyh; + auto l = RegCreateKeyExW( + installAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + path, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS | KEY_WOW64_64KEY, + NULL, + &keyh, + NULL); + if (l) { + wstring error(L"CreateKey"); + error += GetFormattedMessage(l); + throw error; + } + return keyh; +} + +void writeRegKey(HKEY keyh, wstring str) { + auto l = RegSetValueExW( + keyh, + NULL, + 0, + REG_SZ, + (BYTE*)str.c_str(), + (DWORD)((str.size()) * sizeof(wchar_t))); + if (l) { + wstring error(L"WriteValue"); + error += GetFormattedMessage(l); + throw error; + } +} + +void install_firefox(bool installAllUsers, wstring & binpath) { + const wchar_t regpath[] = L"SOFTWARE\\Mozilla\\NativeMessagingHosts\\no.ttyridal.pwvault_gateway"; + + wstring fname = binpath.substr(0, binpath.size() - 4) + L"_ff.json"; + wcerr << L"Create file " << fname.c_str() << endl; + + wofstream f(fname, ofstream::trunc); + f << L"{\n" + << L" \"name\": \"no.ttyridal.pwvault_gateway\",\n" + << L" \"description\" : \"Exposes the OS password vault to masterpassword extension\",\n" + << L" \"path\" : \"" << ReplaceAll(binpath, L"\\", L"\\\\").c_str() << L"\",\n" + << L" \"type\" : \"stdio\",\n" + << L" \"allowed_extensions\" : [\"jid1-pn4AFskf9WBAdA@jetpack\"]\n" + << L"}"; + f.close(); + + wcerr << L"Write registry " << (installAllUsers ? L"HKLM\\" : L"HKCU\\") << regpath << endl; + HKEY keyh = createOrOpenRegKey( + installAllUsers, + regpath); + writeRegKey(keyh, fname); + RegCloseKey(keyh); +} + +void install_chrome(bool installAllUsers, wstring & binpath) { + const wchar_t regpath[] = L"SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\no.ttyridal.pwvault_gateway"; + + wstring fname = binpath.substr(0, binpath.size() - 4) + L"_chrome.json"; + wcerr << L"Create file " << fname.c_str() << endl; + + wofstream f(fname, ofstream::trunc); + f << L"{\n" + << L" \"name\": \"no.ttyridal.pwvault_gateway\",\n" + << L" \"description\" : \"Exposes the OS password vault to masterpassword extension\",\n" + << L" \"path\" : \"" << ReplaceAll(binpath, L"\\", L"\\\\").c_str() << L"\",\n" + << L" \"type\" : \"stdio\",\n" + << L" \"allowed_origins\": [\"chrome-extension://hifbblnjfcimjnlhibannjoclibgedmd/\"]\n" + << L"}"; + f.close(); + + wcerr << L"Write registry " << (installAllUsers ? L"HKLM\\" : L"HKCU\\") << regpath << endl; + HKEY keyh = createOrOpenRegKey( + installAllUsers, + regpath); + writeRegKey(keyh, fname); + RegCloseKey(keyh); +} + +int wmain(int argc, wchar_t * argv[]) +{ + argv = CommandLineToArgvW(GetCommandLine(), &argc); + + if (argc > 1 && (wstring(argv[1]) == wstring(L"test"))) { + _setmode(_fileno(stderr), _O_U16TEXT); + + if (argc > 2 && (wstring(argv[2]) == wstring(L"pwget"))) { + wcerr << L"otuput: " << password_get().c_str() << endl; + } + else if (argc > 3 && (wstring(argv[2]) == wstring(L"pwset"))) { + password_set(wstring(argv[3])); + } + else + wcerr << L"Invalid arguments\n"; + } + else if (argc > 1 && (wstring(argv[1]) == wstring(L"install"))) { + _setmode(_fileno(stderr), _O_U16TEXT); + wstring fname(argv[0]); + bool installAllUsers = argc > 2 && wstring(argv[2]) == wstring(L"global"); + install_firefox(installAllUsers, fname); + install_chrome(installAllUsers, fname); + } + else { + cerr << "Native bridge: "; + for (auto i = 0; i < argc; i++) + cerr << "'" << wstring_to_utf8(argv[i]).c_str() << "'"; + cerr << endl; + set_binary_io(); + native_bridge(); + } + + return 0; +} \ No newline at end of file diff --git a/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj b/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj new file mode 100644 index 0000000..fbe2d6e --- /dev/null +++ b/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {D3DEA12A-3254-480E-9D90-5A75813C1754} + Win32Proj + pwvault_gw + 8.1 + pwvault_gw + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_build\ + $(ProjectName)_debug + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_build\ + $(ProjectName)_debug + + + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_build\ + $(ProjectName) + + + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_build\ + $(ProjectName) + + + + + + Level4 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level4 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level4 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + None + true + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + diff --git a/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj.filters b/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj.filters new file mode 100644 index 0000000..39bd2cf --- /dev/null +++ b/native_bridge/win/pwvault_gw/pwvault_gw.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + diff --git a/native_bridge/win/pwvault_gw_installer/Product.wxs b/native_bridge/win/pwvault_gw_installer/Product.wxs new file mode 100644 index 0000000..94888c1 --- /dev/null +++ b/native_bridge/win/pwvault_gw_installer/Product.wxs @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native_bridge/win/pwvault_gw_installer/pwvault_gw_installer.wixproj b/native_bridge/win/pwvault_gw_installer/pwvault_gw_installer.wixproj new file mode 100644 index 0000000..1eb0060 --- /dev/null +++ b/native_bridge/win/pwvault_gw_installer/pwvault_gw_installer.wixproj @@ -0,0 +1,44 @@ + + + + Debug + x86 + 3.10 + f81fc781-70d9-426b-b381-44a976b37bc6 + 2.0 + pwvault_gw_installer + Package + $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets + $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_wix\ + Debug + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_wix\ + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_wix\ + + + Debug + $(SolutionDir)$(Configuration)\$(Platform)\ + $(SolutionDir)$(Configuration)\$(Platform)_wix\ + + + + + + + \ No newline at end of file