Thunderbird passwordcommand fixed
This commit is contained in:
		
							parent
							
								
									d1dd741f05
								
							
						
					
					
						commit
						ac21c9885e
					
				
							
								
								
									
										274
									
								
								packages/add_passwordcommand_imap.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								packages/add_passwordcommand_imap.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,274 @@
 | 
			
		||||
diff -x __pycache__ -ru thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.cpp thunderbird/thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.cpp
 | 
			
		||||
--- thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.cpp	2025-05-13 15:22:25.000000000 +0200
 | 
			
		||||
+++ thunderbird/thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.cpp	2025-08-21 03:49:50.217872643 +0200
 | 
			
		||||
@@ -41,6 +41,15 @@
 | 
			
		||||
 #include "mozilla/Unused.h"
 | 
			
		||||
 #include "nsIUUIDGenerator.h"
 | 
			
		||||
 #include "nsIArray.h"
 | 
			
		||||
+#include "mozilla/SpinEventLoopUntil.h"
 | 
			
		||||
+#include "nsIProcess.h"
 | 
			
		||||
+#include "mozilla/RandomNum.h"
 | 
			
		||||
+#include "nsIServerSocket.h"
 | 
			
		||||
+#include "nsIAsyncInputStream.h"
 | 
			
		||||
+#include "nsISocketTransport.h"
 | 
			
		||||
+#include "nsIBinaryInputStream.h"
 | 
			
		||||
+#include "nsIObjectInputStream.h"
 | 
			
		||||
+#include "nsDirectoryServiceDefs.h"
 | 
			
		||||
 
 | 
			
		||||
 #define PORT_NOT_SET -1
 | 
			
		||||
 
 | 
			
		||||
@@ -707,12 +716,241 @@
 | 
			
		||||
   return NS_OK;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+nsresult
 | 
			
		||||
+nsMsgIncomingServer::GetPasswordCommand(nsTArray<nsString> &passwordCommand) {
 | 
			
		||||
+  nsString serializedCommand;
 | 
			
		||||
+
 | 
			
		||||
+  nsresult rv = GetUnicharValue("passwordCommand", serializedCommand);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  if (serializedCommand.Length() == 0)
 | 
			
		||||
+    return NS_OK;
 | 
			
		||||
+
 | 
			
		||||
+  // Serialization is achieved by joining the arguments with a comma.
 | 
			
		||||
+  // Commas are themselves allowed to be backslash-espaced.
 | 
			
		||||
+
 | 
			
		||||
+  nsString currentArgument;
 | 
			
		||||
+  bool nextShouldBeEscaped = false;
 | 
			
		||||
+
 | 
			
		||||
+  for (unsigned int i = 0; i < serializedCommand.Length(); i++) {
 | 
			
		||||
+    char c = serializedCommand[i];
 | 
			
		||||
+
 | 
			
		||||
+    switch (c) {
 | 
			
		||||
+      case ',':
 | 
			
		||||
+	if (nextShouldBeEscaped) {
 | 
			
		||||
+	  currentArgument.Append(',');
 | 
			
		||||
+	  nextShouldBeEscaped = false;
 | 
			
		||||
+	} else {
 | 
			
		||||
+	  passwordCommand.AppendElement(currentArgument);
 | 
			
		||||
+	  currentArgument.Truncate();
 | 
			
		||||
+	}
 | 
			
		||||
+	break;
 | 
			
		||||
+
 | 
			
		||||
+      case '\\':
 | 
			
		||||
+	if (nextShouldBeEscaped)
 | 
			
		||||
+	  currentArgument.Append(',');
 | 
			
		||||
+
 | 
			
		||||
+	nextShouldBeEscaped = !nextShouldBeEscaped;
 | 
			
		||||
+	break;
 | 
			
		||||
+
 | 
			
		||||
+      default:
 | 
			
		||||
+	currentArgument.Append(c);
 | 
			
		||||
+	break;
 | 
			
		||||
+    }
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
+  if (nextShouldBeEscaped)
 | 
			
		||||
+    currentArgument.Append('\\');
 | 
			
		||||
+  passwordCommand.AppendElement(currentArgument);
 | 
			
		||||
+
 | 
			
		||||
+  return NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+class PasswordCommandObserver final
 | 
			
		||||
+  : public nsIObserver,
 | 
			
		||||
+    public nsIServerSocketListener,
 | 
			
		||||
+    public nsIInputStreamCallback {
 | 
			
		||||
+  public:
 | 
			
		||||
+    NS_DECL_ISUPPORTS
 | 
			
		||||
+    NS_DECL_NSIOBSERVER
 | 
			
		||||
+    NS_DECL_NSISERVERSOCKETLISTENER
 | 
			
		||||
+    NS_DECL_NSIINPUTSTREAMCALLBACK
 | 
			
		||||
+
 | 
			
		||||
+  private:
 | 
			
		||||
+    bool isCommandDone;
 | 
			
		||||
+    bool passwordReceived;
 | 
			
		||||
+    nsAString& password;
 | 
			
		||||
+    nsTArray<uint8_t> received;
 | 
			
		||||
+
 | 
			
		||||
+  public:
 | 
			
		||||
+    PasswordCommandObserver(nsAString& password);
 | 
			
		||||
+    bool IsDone();
 | 
			
		||||
+  private:
 | 
			
		||||
+    ~PasswordCommandObserver();
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+NS_IMPL_ISUPPORTS(PasswordCommandObserver, nsIObserver, nsIServerSocketListener, nsIInputStreamCallback)
 | 
			
		||||
+
 | 
			
		||||
+PasswordCommandObserver::PasswordCommandObserver(nsAString& password) : password(password) {
 | 
			
		||||
+  isCommandDone = false;
 | 
			
		||||
+  passwordReceived = false;
 | 
			
		||||
+}
 | 
			
		||||
+PasswordCommandObserver::~PasswordCommandObserver() {}
 | 
			
		||||
+
 | 
			
		||||
+bool
 | 
			
		||||
+PasswordCommandObserver::IsDone() {
 | 
			
		||||
+  return isCommandDone && passwordReceived;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+NS_IMETHODIMP
 | 
			
		||||
+PasswordCommandObserver::Observe(nsISupports* aSubject, const char* aTopic,
 | 
			
		||||
+				 const char16_t* aData) {
 | 
			
		||||
+  isCommandDone = true;
 | 
			
		||||
+
 | 
			
		||||
+  return strcmp(aTopic, "process-failed") == 0 ? NS_ERROR_FAILURE : NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+NS_IMETHODIMP
 | 
			
		||||
+PasswordCommandObserver::OnSocketAccepted(nsIServerSocket *aServ, nsISocketTransport *aTransport) {
 | 
			
		||||
+  nsresult rv;
 | 
			
		||||
+
 | 
			
		||||
+  // The socket can be closed. This does not close the existing connection.
 | 
			
		||||
+  rv = aServ->Close();
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  nsCOMPtr<nsIInputStream> stream;
 | 
			
		||||
+  rv = aTransport->OpenInputStream(0, 0, 0, getter_AddRefs(stream));
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  nsCOMPtr<nsIAsyncInputStream> astream;
 | 
			
		||||
+  astream = do_QueryInterface(stream);
 | 
			
		||||
+  rv = astream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  return NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+NS_IMETHODIMP
 | 
			
		||||
+PasswordCommandObserver::OnStopListening(nsIServerSocket *aServ, nsresult aStatus) {
 | 
			
		||||
+  return NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+NS_IMETHODIMP
 | 
			
		||||
+PasswordCommandObserver::OnInputStreamReady(nsIAsyncInputStream *aStream) {
 | 
			
		||||
+  nsresult rv;
 | 
			
		||||
+
 | 
			
		||||
+  int64_t len;
 | 
			
		||||
+  rv = aStream->Available((uint64_t*)&len);
 | 
			
		||||
+  if (NS_FAILED(rv))
 | 
			
		||||
+    // note: aStream->Available() can also return -1.
 | 
			
		||||
+    len = -1;
 | 
			
		||||
+
 | 
			
		||||
+  if (len == -1) {
 | 
			
		||||
+    password.Assign(NS_ConvertUTF8toUTF16((char*)received.Elements(), received.Length()));
 | 
			
		||||
+    passwordReceived = true;
 | 
			
		||||
+  } else {
 | 
			
		||||
+    if (len > 0) {
 | 
			
		||||
+      nsCOMPtr<nsIBinaryInputStream> bin = NS_NewObjectInputStream(aStream);
 | 
			
		||||
+      nsTArray<uint8_t> data;
 | 
			
		||||
+      rv = bin->ReadByteArray(len, data);
 | 
			
		||||
+      NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+      received.AppendElements(data);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    rv = aStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
 | 
			
		||||
+    NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
+  return NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+nsresult
 | 
			
		||||
+nsMsgIncomingServer::RunPasswordCommand(nsTArray<nsString> &passwordCommand, nsAString& password) {
 | 
			
		||||
+  nsresult rv;
 | 
			
		||||
+
 | 
			
		||||
+  nsCOMPtr<nsIFile> socketFile;
 | 
			
		||||
+  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(socketFile));
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+  nsAutoString tempSocketName;
 | 
			
		||||
+  uint64_t randomSocketName = mozilla::RandomUint64().valueOrFrom([] {
 | 
			
		||||
+    return 0;
 | 
			
		||||
+  });
 | 
			
		||||
+  const char* alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
 | 
			
		||||
+  tempSocketName.AppendPrintf(
 | 
			
		||||
+    "tmp-%c%c%c.sock",
 | 
			
		||||
+    alphabet[randomSocketName % 36],
 | 
			
		||||
+    alphabet[(randomSocketName / 36) % 36],
 | 
			
		||||
+    alphabet[(randomSocketName / (36*36)) % 36]
 | 
			
		||||
+  );
 | 
			
		||||
+  socketFile->AppendRelativePath(tempSocketName);
 | 
			
		||||
+
 | 
			
		||||
+  nsCOMPtr<nsIServerSocket> socket =
 | 
			
		||||
+      do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
 | 
			
		||||
+  socket->InitWithFilename(socketFile, 0600, -1);
 | 
			
		||||
+
 | 
			
		||||
+  auto executable = passwordCommand[0];
 | 
			
		||||
+  nsCOMPtr<nsIFile> executableFile =
 | 
			
		||||
+    do_CreateInstance("@mozilla.org/file/local;1", &rv);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+  executableFile->InitWithPath(executable);
 | 
			
		||||
+
 | 
			
		||||
+  nsCOMPtr<nsIProcess> process =
 | 
			
		||||
+    do_CreateInstance("@mozilla.org/process/util;1", &rv);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+  rv = process->Init(executableFile);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  auto observer = new PasswordCommandObserver(password);
 | 
			
		||||
+
 | 
			
		||||
+  socket->AsyncListen(observer);
 | 
			
		||||
+
 | 
			
		||||
+  auto argsCount = passwordCommand.Length();
 | 
			
		||||
+  const char** args = new const char*[argsCount];
 | 
			
		||||
+  for (unsigned int i = 0; i < argsCount - 1; i++) {
 | 
			
		||||
+    NS_ConvertUTF16toUTF8 argUtf8(passwordCommand[i + 1]);
 | 
			
		||||
+    args[i] = strdup(argUtf8.get());
 | 
			
		||||
+  }
 | 
			
		||||
+  nsString socketPath;
 | 
			
		||||
+  rv = socketFile->GetPath(socketPath);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+  NS_ConvertUTF16toUTF8 socketPathUtf8(socketPath);
 | 
			
		||||
+  args[argsCount - 1] = strdup(socketPathUtf8.get());
 | 
			
		||||
+
 | 
			
		||||
+  rv = process->RunAsync(args, argsCount, observer, false);
 | 
			
		||||
+  if (NS_FAILED(rv))
 | 
			
		||||
+    return rv;
 | 
			
		||||
+
 | 
			
		||||
+  mozilla::SpinEventLoopUntil("nsMsgIncomingServer::RunPasswordCommand"_ns, [&]() {
 | 
			
		||||
+    return observer->IsDone();
 | 
			
		||||
+  });
 | 
			
		||||
+
 | 
			
		||||
+  for (unsigned int i = 0; i < argsCount; i++)
 | 
			
		||||
+    free((void*)args[i]);
 | 
			
		||||
+  delete[] args;
 | 
			
		||||
+
 | 
			
		||||
+  return NS_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 NS_IMETHODIMP
 | 
			
		||||
 nsMsgIncomingServer::GetPasswordWithUI(const nsAString& aPromptMessage,
 | 
			
		||||
                                        const nsAString& aPromptTitle,
 | 
			
		||||
                                        nsAString& aPassword) {
 | 
			
		||||
   nsresult rv = NS_OK;
 | 
			
		||||
 
 | 
			
		||||
+  nsTArray<nsString> passwordCommand;
 | 
			
		||||
+  rv = GetPasswordCommand(passwordCommand);
 | 
			
		||||
+  NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+  if (passwordCommand.Length() > 0) {
 | 
			
		||||
+    rv = RunPasswordCommand(passwordCommand, aPassword);
 | 
			
		||||
+    NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+    rv = SetPassword(aPassword);
 | 
			
		||||
+    NS_ENSURE_SUCCESS(rv, rv);
 | 
			
		||||
+
 | 
			
		||||
+    return NS_OK;
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
   if (m_password.IsEmpty()) {
 | 
			
		||||
     // let's see if we have the password in the password manager and
 | 
			
		||||
     // can avoid this prompting thing. This makes it easier to get embedders
 | 
			
		||||
diff -x __pycache__ -ru thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.h thunderbird/thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.h
 | 
			
		||||
--- thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.h	2025-05-13 15:22:25.000000000 +0200
 | 
			
		||||
+++ thunderbird/thunderbird-128.10.1/comm/mailnews/base/src/nsMsgIncomingServer.h	2025-08-19 12:39:19.236805257 +0200
 | 
			
		||||
@@ -48,6 +48,9 @@
 | 
			
		||||
   nsCString m_serverKey;
 | 
			
		||||
   bool m_hasShutDown;
 | 
			
		||||
 
 | 
			
		||||
+  nsresult GetPasswordCommand(nsTArray<nsString> &passwordCommand);
 | 
			
		||||
+  nsresult RunPasswordCommand(nsTArray<nsString> &passwordCommand, nsAString& password);
 | 
			
		||||
+
 | 
			
		||||
   // Sets m_password, if password found. Can return NS_ERROR_ABORT if the
 | 
			
		||||
   // user cancels the master password dialog.
 | 
			
		||||
   nsresult GetPasswordWithoutUI();
 | 
			
		||||
							
								
								
									
										298
									
								
								packages/add_passwordcommand_smtp.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								packages/add_passwordcommand_smtp.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,298 @@
 | 
			
		||||
--- a/comm/mailnews/base/src/MailAuthenticator.sys.mjs
 | 
			
		||||
+++ b/comm/mailnews/base/src/MailAuthenticator.sys.mjs
 | 
			
		||||
@@ -229,7 +229,7 @@
 | 
			
		||||
     this._server.forgetPassword();
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
-  getPassword() {
 | 
			
		||||
+  async getPassword() {
 | 
			
		||||
     if (this._server.password) {
 | 
			
		||||
       return this._server.password;
 | 
			
		||||
     }
 | 
			
		||||
@@ -261,8 +261,8 @@
 | 
			
		||||
    *
 | 
			
		||||
    * @returns {string}
 | 
			
		||||
    */
 | 
			
		||||
-  getByteStringPassword() {
 | 
			
		||||
-    return MailStringUtils.stringToByteString(this.getPassword());
 | 
			
		||||
+  async getByteStringPassword() {
 | 
			
		||||
+    return MailStringUtils.stringToByteString(await this.getPassword());
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   /**
 | 
			
		||||
@@ -270,10 +270,12 @@
 | 
			
		||||
    *
 | 
			
		||||
    * @returns {string}
 | 
			
		||||
    */
 | 
			
		||||
-  getPlainToken() {
 | 
			
		||||
+  async getPlainToken() {
 | 
			
		||||
     // According to rfc4616#section-2, password should be UTF-8 BinaryString
 | 
			
		||||
     // before base64 encoded.
 | 
			
		||||
-    return btoa("\0" + this.username + "\0" + this.getByteStringPassword());
 | 
			
		||||
+    return btoa(
 | 
			
		||||
+      "\0" + this.username + "\0" + (await this.getByteStringPassword())
 | 
			
		||||
+    );
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   async getOAuthToken() {
 | 
			
		||||
--- a/comm/mailnews/compose/src/SmtpServer.sys.mjs
 | 
			
		||||
+++ b/comm/mailnews/compose/src/SmtpServer.sys.mjs
 | 
			
		||||
@@ -7,9 +7,22 @@
 | 
			
		||||
 
 | 
			
		||||
 const lazy = {};
 | 
			
		||||
 ChromeUtils.defineESModuleGetters(lazy, {
 | 
			
		||||
+  FileUtils: "resource:///modules/FileUtils.sys.mjs",
 | 
			
		||||
   SmtpClient: "resource:///modules/SmtpClient.sys.mjs",
 | 
			
		||||
 });
 | 
			
		||||
 
 | 
			
		||||
+const UnixServerSocket = Components.Constructor(
 | 
			
		||||
+  "@mozilla.org/network/server-socket;1",
 | 
			
		||||
+  "nsIServerSocket",
 | 
			
		||||
+  "initWithFilename"
 | 
			
		||||
+);
 | 
			
		||||
+const currentThread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
 | 
			
		||||
+const BinaryInputStream = Components.Constructor(
 | 
			
		||||
+  "@mozilla.org/binaryinputstream;1",
 | 
			
		||||
+  "nsIBinaryInputStream",
 | 
			
		||||
+  "setInputStream"
 | 
			
		||||
+);
 | 
			
		||||
+
 | 
			
		||||
 /**
 | 
			
		||||
  * This class represents a single SMTP server.
 | 
			
		||||
  *
 | 
			
		||||
@@ -318,7 +331,161 @@
 | 
			
		||||
     this._password = password;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
-  getPasswordWithUI(promptMessage, promptTitle) {
 | 
			
		||||
+  getPasswordCommand() {
 | 
			
		||||
+    let serializedCommand = this._getCharPrefWithDefault("passwordCommand");
 | 
			
		||||
+    if (serializedCommand === "")
 | 
			
		||||
+      return null;
 | 
			
		||||
+
 | 
			
		||||
+    // Serialization is achieved by joining the arguments with a comma.
 | 
			
		||||
+    // Comma are themselves allowed to be backslash-espaced.
 | 
			
		||||
+
 | 
			
		||||
+    let currentArgument = "";
 | 
			
		||||
+    let nextShouldBeEscaped = false;
 | 
			
		||||
+    let commandArguments = [];
 | 
			
		||||
+
 | 
			
		||||
+    for (let i = 0; i < serializedCommand.length; i++) {
 | 
			
		||||
+      let c = serializedCommand[i];
 | 
			
		||||
+
 | 
			
		||||
+      switch (c) {
 | 
			
		||||
+        case ',':
 | 
			
		||||
+          if (nextShouldBeEscaped) {
 | 
			
		||||
+            currentArgument += ',';
 | 
			
		||||
+            nextShouldBeEscaped = false;
 | 
			
		||||
+          } else {
 | 
			
		||||
+            commandArguments.push(currentArgument);
 | 
			
		||||
+            currentArgument = '';
 | 
			
		||||
+          }
 | 
			
		||||
+          break;
 | 
			
		||||
+
 | 
			
		||||
+        case '\\':
 | 
			
		||||
+          if (nextShouldBeEscaped)
 | 
			
		||||
+            currentArgument += '\\';
 | 
			
		||||
+
 | 
			
		||||
+          nextShouldBeEscaped = !nextShouldBeEscaped;
 | 
			
		||||
+          break;
 | 
			
		||||
+
 | 
			
		||||
+        default:
 | 
			
		||||
+          currentArgument += c;
 | 
			
		||||
+          break;
 | 
			
		||||
+      }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    if (nextShouldBeEscaped)
 | 
			
		||||
+      currentArgument += '\\';
 | 
			
		||||
+    commandArguments.push(currentArgument);
 | 
			
		||||
+
 | 
			
		||||
+    return commandArguments;
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
+  async runPasswordCommand(passwordCommand) {
 | 
			
		||||
+    let executable = passwordCommand[0];
 | 
			
		||||
+    let args = passwordCommand.splice(1);
 | 
			
		||||
+
 | 
			
		||||
+    let executableFile = new lazy.FileUtils.File(executable);
 | 
			
		||||
+
 | 
			
		||||
+    function genSocketFile() {
 | 
			
		||||
+      let tmpDir = lazy.FileUtils.getDir("TmpD", [], false);
 | 
			
		||||
+      let random = Math.round(Math.random() * 36 ** 3).toString(36);
 | 
			
		||||
+      return new lazy.FileUtils.File(
 | 
			
		||||
+        PathUtils.join(tmpDir.path, `tmp-${random}.sock`)
 | 
			
		||||
+      );
 | 
			
		||||
+    }
 | 
			
		||||
+    let socketFile = genSocketFile();
 | 
			
		||||
+
 | 
			
		||||
+    let socket = new UnixServerSocket(
 | 
			
		||||
+      socketFile,
 | 
			
		||||
+      parseInt("600", 8),
 | 
			
		||||
+      -1
 | 
			
		||||
+    );
 | 
			
		||||
+    
 | 
			
		||||
+    var process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
 | 
			
		||||
+    process.init(executableFile);
 | 
			
		||||
+    let processPromise = new Promise((resolve, reject) => {
 | 
			
		||||
+      process.runAsync(
 | 
			
		||||
+	args.concat(socketFile.path),
 | 
			
		||||
+	args.length + 1,
 | 
			
		||||
+	{
 | 
			
		||||
+	  observe(subject, topic, data) {
 | 
			
		||||
+	    switch (topic) {
 | 
			
		||||
+	      case "process-finished":
 | 
			
		||||
+		resolve();
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	      case "process-failed":
 | 
			
		||||
+		reject();
 | 
			
		||||
+		break;
 | 
			
		||||
+	    }
 | 
			
		||||
+	  }
 | 
			
		||||
+	},
 | 
			
		||||
+	false
 | 
			
		||||
+      );
 | 
			
		||||
+    });
 | 
			
		||||
+
 | 
			
		||||
+    let passwordPromise = new Promise((resolve, reject) => {
 | 
			
		||||
+      socket.asyncListen({
 | 
			
		||||
+        "onSocketAccepted": (server, transport) => {
 | 
			
		||||
+          // The socket can be closed. This does not close the existing connection.
 | 
			
		||||
+          socket.close();
 | 
			
		||||
+
 | 
			
		||||
+          var stream = transport.openInputStream(0, 0, 0);
 | 
			
		||||
+
 | 
			
		||||
+	  let received = [];
 | 
			
		||||
+          let observer = {
 | 
			
		||||
+            onInputStreamReady(stream) {
 | 
			
		||||
+              let len = 0;
 | 
			
		||||
+              try {
 | 
			
		||||
+                len = stream.available();
 | 
			
		||||
+              } catch (e) {
 | 
			
		||||
+		// note: stream.available() can also return -1.
 | 
			
		||||
+		len = -1;
 | 
			
		||||
+              }
 | 
			
		||||
+
 | 
			
		||||
+              if (len == -1) {
 | 
			
		||||
+                let decoder = new TextDecoder();
 | 
			
		||||
+                let result = decoder.decode(new Uint8Array(received));
 | 
			
		||||
+
 | 
			
		||||
+                resolve(result);
 | 
			
		||||
+              } else {
 | 
			
		||||
+                if (len > 0) {
 | 
			
		||||
+                  let bin = new BinaryInputStream(stream);
 | 
			
		||||
+		  let data = Array.from(bin.readByteArray(len));
 | 
			
		||||
+                  received = received.concat(data);
 | 
			
		||||
+                }
 | 
			
		||||
+
 | 
			
		||||
+                stream.asyncWait(observer, 0, 0, currentThread);
 | 
			
		||||
+              }
 | 
			
		||||
+            }
 | 
			
		||||
+          };
 | 
			
		||||
+          stream.asyncWait(observer, 0, 0, currentThread);
 | 
			
		||||
+        }
 | 
			
		||||
+      });
 | 
			
		||||
+    });
 | 
			
		||||
+
 | 
			
		||||
+    let [_, result] = await Promise.allSettled([
 | 
			
		||||
+      processPromise,
 | 
			
		||||
+      passwordPromise,
 | 
			
		||||
+    ]);
 | 
			
		||||
+
 | 
			
		||||
+    socketFile.remove(false);
 | 
			
		||||
+
 | 
			
		||||
+    if (result.status == "fulfilled")
 | 
			
		||||
+      return result.value;
 | 
			
		||||
+    else
 | 
			
		||||
+      return Promise.reject(result.reason);
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
+  async getPasswordWithUI(promptMessage, promptTitle) {
 | 
			
		||||
+    let passwordCommand = this.getPasswordCommand();
 | 
			
		||||
+    if (passwordCommand !== null) {
 | 
			
		||||
+      let password = await this.runPasswordCommand(passwordCommand);
 | 
			
		||||
+
 | 
			
		||||
+      if (password === null)
 | 
			
		||||
+        throw Components.Exception("Password command failure", Cr.NS_ERROR_ABORT);
 | 
			
		||||
+
 | 
			
		||||
+      this.password = password;
 | 
			
		||||
+      return this.password;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     // This prompt has a checkbox for saving password.
 | 
			
		||||
     const authPrompt = Cc["@mozilla.org/messenger/msgAuthPrompt;1"].getService(
 | 
			
		||||
       Ci.nsIAuthPrompt
 | 
			
		||||
--- a/comm/mailnews/compose/src/SmtpClient.sys.mjs
 | 
			
		||||
+++ b/comm/mailnews/compose/src/SmtpClient.sys.mjs
 | 
			
		||||
@@ -362,7 +362,7 @@
 | 
			
		||||
    *
 | 
			
		||||
    * @param {string} chunk Chunk of data received from the server
 | 
			
		||||
    */
 | 
			
		||||
-  _parse(chunk) {
 | 
			
		||||
+  async _parse(chunk) {
 | 
			
		||||
     // Lines should always end with <CR><LF> but you never know, might be only <LF> as well
 | 
			
		||||
     var lines = (this._parseRemainder + (chunk || "")).split(/\r?\n/);
 | 
			
		||||
     this._parseRemainder = lines.pop(); // not sure if the line has completely arrived yet
 | 
			
		||||
@@ -399,14 +399,14 @@
 | 
			
		||||
             success: statusCode >= 200 && statusCode < 300,
 | 
			
		||||
           };
 | 
			
		||||
 
 | 
			
		||||
-          this._onCommand(response);
 | 
			
		||||
+          await this._onCommand(response);
 | 
			
		||||
           this._parseBlock = {
 | 
			
		||||
             data: [],
 | 
			
		||||
             statusCode: null,
 | 
			
		||||
           };
 | 
			
		||||
         }
 | 
			
		||||
       } else {
 | 
			
		||||
-        this._onCommand({
 | 
			
		||||
+        await this._onCommand({
 | 
			
		||||
           success: false,
 | 
			
		||||
           statusCode: this._parseBlock.statusCode || null,
 | 
			
		||||
           data: [lines[i]].join("\n"),
 | 
			
		||||
@@ -456,7 +456,7 @@
 | 
			
		||||
     // rejects AUTH PLAIN then closes the connection, the client then sends AUTH
 | 
			
		||||
     // LOGIN. This line guarantees onclose is called before sending AUTH LOGIN.
 | 
			
		||||
     await new Promise(resolve => setTimeout(resolve));
 | 
			
		||||
-    this._parse(stringPayload);
 | 
			
		||||
+    await this._parse(stringPayload);
 | 
			
		||||
   };
 | 
			
		||||
 
 | 
			
		||||
   /**
 | 
			
		||||
@@ -732,7 +732,7 @@
 | 
			
		||||
         this.logger.debug("Authentication via AUTH PLAIN");
 | 
			
		||||
         this._currentAction = this._actionAUTHComplete;
 | 
			
		||||
         this._sendCommand(
 | 
			
		||||
-          "AUTH PLAIN " + this._authenticator.getPlainToken(),
 | 
			
		||||
+          "AUTH PLAIN " + (await this._authenticator.getPlainToken()),
 | 
			
		||||
           true
 | 
			
		||||
         );
 | 
			
		||||
         return;
 | 
			
		||||
@@ -1065,7 +1065,7 @@
 | 
			
		||||
    * @param {{statusCode: number, data: string}} command - Parsed command from
 | 
			
		||||
    *   the server.
 | 
			
		||||
    */
 | 
			
		||||
-  _actionAUTH_LOGIN_PASS(command) {
 | 
			
		||||
+  async _actionAUTH_LOGIN_PASS(command) {
 | 
			
		||||
     if (
 | 
			
		||||
       command.statusCode !== 334 ||
 | 
			
		||||
       (command.data !== btoa("Password:") && command.data !== btoa("password:"))
 | 
			
		||||
@@ -1075,7 +1075,7 @@
 | 
			
		||||
     }
 | 
			
		||||
     this.logger.debug("AUTH LOGIN PASS");
 | 
			
		||||
     this._currentAction = this._actionAUTHComplete;
 | 
			
		||||
-    let password = this._getPassword();
 | 
			
		||||
+    let password = await this._getPassword();
 | 
			
		||||
     if (
 | 
			
		||||
       !Services.prefs.getBoolPref(
 | 
			
		||||
         "mail.smtp_login_pop3_user_pass_auth_is_latin1",
 | 
			
		||||
@@ -1104,7 +1104,7 @@
 | 
			
		||||
     }
 | 
			
		||||
     this._currentAction = this._actionAUTHComplete;
 | 
			
		||||
     this._sendCommand(
 | 
			
		||||
-      this._authenticator.getCramMd5Token(this._getPassword(), command.data),
 | 
			
		||||
+      this._authenticator.getCramMd5Token(await this._getPassword(), command.data),
 | 
			
		||||
       true
 | 
			
		||||
     );
 | 
			
		||||
   }
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
    ./locale.nix
 | 
			
		||||
    ./ssh.nix
 | 
			
		||||
    ./email.nix
 | 
			
		||||
    ./git.nix
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  nix.settings.experimental-features = [
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@
 | 
			
		||||
      };
 | 
			
		||||
      smtp = {
 | 
			
		||||
        host = "smtp.hadoly.fr";
 | 
			
		||||
        port = 443;
 | 
			
		||||
        port = 465;
 | 
			
		||||
        tls.enable = true;
 | 
			
		||||
      };
 | 
			
		||||
      primary = true;
 | 
			
		||||
@ -34,7 +34,7 @@
 | 
			
		||||
      };
 | 
			
		||||
      smtp = {
 | 
			
		||||
        host = "mail.mailo.com";
 | 
			
		||||
        port = 443;
 | 
			
		||||
        port = 465;
 | 
			
		||||
        tls.enable = true;
 | 
			
		||||
      };
 | 
			
		||||
      userName = "samyavrillon@netcourrier.com";
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								profiles/basic/git.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								profiles/basic/git.nix
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
{config, lib, pkgs, ...}: {
 | 
			
		||||
 | 
			
		||||
home-manager.users.mysaa.programs.git = {
 | 
			
		||||
  enable = true;
 | 
			
		||||
  userEmail = "mysaa@hadoly.fr";
 | 
			
		||||
  userName = "Mysaa Java";
 | 
			
		||||
 | 
			
		||||
  signing.key = "880352F5FD83DF24F41413CC4E77725580DA73CE";
 | 
			
		||||
 | 
			
		||||
  aliases = {
 | 
			
		||||
    l = "log --oneline --graph";
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,12 +1,16 @@
 | 
			
		||||
{config, lib, pkgs, ...}: {
 | 
			
		||||
 | 
			
		||||
programs.ssh = {
 | 
			
		||||
  extraConfig = "
 | 
			
		||||
  extraConfig = ''
 | 
			
		||||
    Host git-ssh.hadoly.fr
 | 
			
		||||
      Hostname git-ssh.hadoly.fr
 | 
			
		||||
      IdentityFile /run/secrets/ssh/mysaa@git.hadoly.fr
 | 
			
		||||
      Port 6900
 | 
			
		||||
  ";
 | 
			
		||||
 | 
			
		||||
    Host github.com
 | 
			
		||||
      HostName github.com
 | 
			
		||||
      IdentityFile /run/secrets/ssh/MysaaJava@github.com
 | 
			
		||||
  '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,10 @@
 | 
			
		||||
    discord
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  environment.plasma6.excludePackages = with pkgs.kdePackages; [
 | 
			
		||||
    elisa
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  home-manager.users.mysaa.home.packages = with pkgs; [
 | 
			
		||||
    firefox
 | 
			
		||||
    vlc
 | 
			
		||||
@ -23,14 +27,57 @@
 | 
			
		||||
        edwinkofler.vscode-hyperupcall-pack-java
 | 
			
		||||
      ];
 | 
			
		||||
    })
 | 
			
		||||
    keepassxc
 | 
			
		||||
    libreoffice
 | 
			
		||||
    #hyphenDicts.fr_FR
 | 
			
		||||
    hyphenDicts.en_US
 | 
			
		||||
    hyphenDicts.de_DE
 | 
			
		||||
    steam
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  home-manager.users.mysaa.services.kdeconnect.enable = true;
 | 
			
		||||
  # We open kdeconnect ports
 | 
			
		||||
  networking.firewall = rec {
 | 
			
		||||
    allowedTCPPortRanges = [ { from = 1714; to = 1764; } ];
 | 
			
		||||
    allowedUDPPortRanges = allowedTCPPortRanges;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  home-manager.users.mysaa.accounts.email.accounts."hadoly".thunderbird.enable = true;
 | 
			
		||||
  home-manager.users.mysaa.accounts.email.accounts."personal".thunderbird.enable = true;
 | 
			
		||||
  home-manager.users.mysaa.programs.thunderbird = {
 | 
			
		||||
    enable = true;
 | 
			
		||||
    profiles.default = {
 | 
			
		||||
      isDefault = true;
 | 
			
		||||
      settings = {}
 | 
			
		||||
        // lib.attrsets.concatMapAttrs (
 | 
			
		||||
          _: account:
 | 
			
		||||
          lib.optionalAttrs (account.passwordCommand != null) (
 | 
			
		||||
            let
 | 
			
		||||
              id = builtins.hashString "sha256" account.name;
 | 
			
		||||
              command = lib.concatStringsSep " " account.passwordCommand;
 | 
			
		||||
              passwordScript = pkgs.writeShellScript "get-password.sh" ''
 | 
			
		||||
                ${command} | tr -d $'\n' | ${pkgs.netcat}/bin/nc -w 0 -U $1
 | 
			
		||||
              '';
 | 
			
		||||
            in
 | 
			
		||||
            lib.optionalAttrs (account.smtp != null) {
 | 
			
		||||
              "mail.smtpserver.smtp_${id}.passwordCommand" = toString passwordScript;
 | 
			
		||||
            }
 | 
			
		||||
            // lib.optionalAttrs (account.imap != null) {
 | 
			
		||||
              "mail.server.server_${id}.passwordCommand" = toString passwordScript;
 | 
			
		||||
            }
 | 
			
		||||
          )
 | 
			
		||||
        ) config.home-manager.users.mysaa.accounts.email.accounts;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  home-manager.users.mysaa.nixpkgs.overlays = [
 | 
			
		||||
    (final: prev: {
 | 
			
		||||
      thunderbird-unwrapped = prev.thunderbird-unwrapped.overrideAttrs {
 | 
			
		||||
        patches = (prev.thunderbird-unwrapped.patches or [ ]) ++ [
 | 
			
		||||
          ../../packages/add_passwordcommand_smtp.patch
 | 
			
		||||
          ../../packages/add_passwordcommand_imap.patch
 | 
			
		||||
        ];
 | 
			
		||||
      };
 | 
			
		||||
    })
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user