diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..313d462
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,72 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ "master" ]
+ schedule:
+ - cron: '33 17 * * 0'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+
+ # If the Autobuild fails above, remove it and uncomment the following three lines.
+ # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
+
+ # - run: |
+ # echo "Run, Build Application using script"
+ # ./location_of_script_within_repo/buildscript.sh
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/OnePassword.NET/OnePassword.NET.csproj b/OnePassword.NET/OnePassword.NET.csproj
index dffbd99..abc2816 100644
--- a/OnePassword.NET/OnePassword.NET.csproj
+++ b/OnePassword.NET/OnePassword.NET.csproj
@@ -1,33 +1,37 @@
-
- net5.0;netstandard2.0;net45;net40;net35;net20
- OnePassword
- OnePassword.NET
- OnePassword.NET
- Jean-Sebastien Carle
- Jean-Sebastien Carle
- OnePassword.NET
- 1Password CLI Wrapper
- 1.0.280
- 1.0.280.0
- 1.0.280.0
- Copyright © Jean-Sebastien Carle 2021
- https://github.com/jscarle/OnePassword.NET
- git
- 1Password OnePassword
- LICENSE.md
-
+
+ net5.0;netstandard2.0;net45;net40;net35;net20
+ OnePassword
+ OnePassword.NET
+ OnePassword.NET
+ Jean-Sebastien Carle
+ Jean-Sebastien Carle
+ OnePassword.NET
+ 1Password CLI Wrapper
+ 1.1.1
+ 1.1.1.0
+ 1.1.1.0
+ Copyright © Jean-Sebastien Carle 2021-2022
+ https://github.com/jscarle/OnePassword.NET
+ git
+ 1Password OnePassword
+ LICENSE.md
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
-
-
- True
-
-
-
-
diff --git a/OnePassword.NET/OnePasswordManager.cs b/OnePassword.NET/OnePasswordManager.cs
index 1c4a543..58740a1 100644
--- a/OnePassword.NET/OnePasswordManager.cs
+++ b/OnePassword.NET/OnePasswordManager.cs
@@ -5,6 +5,7 @@
using System.IO.Compression;
using System.Text;
using System.Text.RegularExpressions;
+using System.Threading;
using Newtonsoft.Json;
using OnePassword.Documents;
using OnePassword.Groups;
@@ -17,6 +18,7 @@ namespace OnePassword
{
public class OnePasswordManager
{
+ private readonly TimeSpan _totpProcessStartupTimeout = TimeSpan.FromMilliseconds(1000);
private readonly string _opPath;
private readonly bool _verbose;
private string _shorthand;
@@ -223,7 +225,7 @@ public Template GetTemplate(Template template)
{
template.Details = JsonConvert.DeserializeObject(Op($"get template \"{template.Name}\""));
return template;
- }
+ }
public User GetUser(User user) => JsonConvert.DeserializeObject(Op($"get user \"{user.Uuid}\""));
@@ -308,6 +310,16 @@ public ItemList ListItems(Vault vault, Template template, string tag, bool inclu
public void RemoveUser(User user, Group group) => Op($"remove user \"{user.Uuid}\" \"{group.Uuid}\"");
public void SignIn(string domain, string email, string secretKey, string password, string shorthand = "")
+ {
+ SignIn(domain, email, secretKey, password, "", shorthand);
+ }
+
+ public void SignInTotp(string domain, string email, string secretKey, string password, string totp, string shorthand = "")
+ {
+ SignIn(domain, email, secretKey, password, totp, shorthand);
+ }
+
+ private void SignIn(string domain, string email, string secretKey, string password, string totp, string shorthand)
{
Regex opDeviceRegex = new Regex("OP_DEVICE=(?[a-z0-9]+)");
@@ -315,12 +327,12 @@ public void SignIn(string domain, string email, string secretKey, string passwor
if (!string.IsNullOrEmpty(shorthand))
command += $" --shorthand {shorthand}";
- string result = Op(command, password, true);
+ string result = Op(command, new string[] { password, totp }, true);
if (result.Contains("No saved device ID."))
{
string deviceUuid = opDeviceRegex.Match(result).Groups["UUID"].Value;
Environment.SetEnvironmentVariable("OP_DEVICE", deviceUuid);
- result = Op(command, password);
+ result = Op(command, new string[] { password, totp });
}
if (result.StartsWith("[ERROR]"))
@@ -399,6 +411,12 @@ private static string GetStandardOutput(Process process)
private string Op(string command, string input = "", bool returnError = false)
{
+ return Op(command, new string[] { input });
+ }
+
+ private string Op(string command, string[] input, bool returnError = false)
+ {
+
string arguments = command;
if (!string.IsNullOrEmpty(_sessionId))
arguments += $" --session {_sessionId}";
@@ -423,8 +441,17 @@ private string Op(string command, string input = "", bool returnError = false)
if (process is null)
throw new Exception($"Could not start process for {_opPath}.");
- if (input.Length > 0)
- process.StandardInput.WriteLine(input);
+ if (input != null && input.Length > 0)
+ {
+ if (input.Length > 1)
+ Thread.Sleep(_totpProcessStartupTimeout);
+
+ foreach (var inputLine in input)
+ {
+ process.StandardInput.WriteLine(inputLine);
+ process.StandardInput.Flush();
+ }
+ }
string output = GetStandardOutput(process);
if (_verbose)