JavaScript syncronicity: Combining onAuthRequired

2019-01-29 10:41发布

I have this problem ... and I've been trying to get a username and password pair passed to background.js of my extension. The process goes as follows:

  1. A Credentials Server (CS) is started up with encrypted credential tokens
  2. Selenium opens the browser with custom extension
  3. The extension is triggered onAuthRequired
  4. The Native Messaging Host (NMH) starts then receives a 'ready' message
  5. The NMH uses a simple protocol to request tokens from the CS
  6. The NMH decrypts the tokens
  7. The NMH passes the credentials to background.js
  8. background.js returns the credentials to chrome
  9. Authentication magic happens on the remote server

I have solved everything right up to 6 ... maybe 7. The issue is that I am not able to actually capture what the NMH is sending. It seems to be that either the credentials are not formatted correctly, thus they're being rejected or there's a problem with how the JavaScript side is put together and so it's just a case of broken code. It's also possible that what I intend is not at all possible ... though I doubt that is the case.

I will provide as much code as I can ... and while I appreciate any help, I am happy to get a generic example which can be modified in my own time.

Got a better approach? I'm all ears! Happy to create a new question to address other ideas.


EDIT 1.0: I should add that, when run, the alert at line 9 does popup. When modified to read:

window.alert(String(response));

I get [object Object]

EDIT 2.0: I changed window.alert(String(response)); to window.alert(JSON.stringify(response)); and it produced the expected outcome: {"username":"\"some_user\"","password":"\"1Password\"} I expect this would translate to '{username:"some_user",password:"1Password"}'

There appears to be a problem passing the value of response to creds since the NMH fails to run at all once I try to access the username/password property of creds outside the callback. This is probably a scope issue ...

Edit 3.0: I found the issue - it's a synchronicity problem. I've found many, many questions on this - I'll answer this when I've come up with a work around myself. Feel free to answer with a solution, should you have one.


Current background.js (not working)

chrome.webRequest.onAuthRequired.addListener(() => {
 var hostName = "aardvark_nm_host";
 var creds = null;

 chrome.runtime.sendNativeMessage(
   hostName,
   { text: "Ready" },
   function(response){
     window.alert("response");
     console.log(response);
     creds = JSON.parse(response);
   }
 );
 return {authCredentials: creds};
},
 {urls: ["<all_urls>"]},
 ['blocking']
);

Current aardvark_nm_host.py (Probably working)

#!/usr/bin/env python

from locksmith import decrypt_token, KEYFILE
import socket
import struct
import sys
import json

PORT = 9999
ADDR = 'localhost'

ERRMSG = {"username":"ERROR", "password":"password"}

def report_string(string):
  def transceive(signal):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server = (ADDR, PORT)
    sock.connect(server)

    try:
      sock.sendall(signal)
    except Exception as e:
      print >>sys.stderr, e
      sock.close()
    try:
      sock.sendall(string)
      sock.close()
    except Exception as e:
      print >>sys.stderr, e
      sock.close()

  transceive('S')

def get_tokens():
  def recv_burst(sock):
    total_data = []
    while True:
      data = sock.recv(1024)
      if not data:
        break
      total_data.append(data)
    return ''.join(total_data)

  def transceive(signal):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server = (ADDR, PORT)
    sock.connect(server)

    try:
      sock.sendall(signal)
      message = recv_burst(sock)

    except Exception as e:
      report_string(e)

    finally:
      sock.close()
      
    return message

  try:
    username = transceive('U')
    username = decrypt_token(username)
    report_string(username)
  except Exception as e:
    report_string(str(e))
    username = "TOKEN_ERROR"
  try:
    password = transceive('P')
    password = decrypt_token(password)
    report_string(password)
  except Exception as e:
    report_string(str(e))
    password = "TOKEN_ERROR"

  return {"username":username, "password":password}

def read_message():
  text_length = sys.stdin.read(4)
  if len(text_length) == 0:
    sys.exit(0)

  text_length = struct.unpack('@I', text_length)[0]
  text = sys.stdin.read(text_length)
  return json.loads(text)
  
def encode_message(message):
  encoded_content = json.dumps(message)
  encoded_length = struct.pack('@I', len(encoded_content))
  return {'length': encoded_length, 'content': encoded_content}
  
def send_message(encoded_message):
  sys.stdout.write(encoded_message['length'])
  sys.stdout.write(encoded_message['content'])
  sys.stdout.flush()

def interpretation(message):
  return message["text"] == "Ready"

while True:
  received_message = read_message()
  report_string(received_message)

  if interpretation(received_message):
    creds = get_tokens()
    send_message(encode_message(creds))
    creds = None
  else:
    send_message(encode_message(ERRMSG))

Current extension manifest.json

{
    "version": "1.0.0",
    "manifest_version": 2,
    "name": "authvark",
    "permissions": [
        "<all_urls>",
        "webRequest",
        "webRequestBlocking",
        "nativeMessaging"
    ],
    "background": {
        "scripts": ["background.js"],
        "persistent": false
    }
}

native-messaging-hosts/manifest.json

{
  "name": "aardvark_nm_host",
  "description": "Intermediary Credential Host",
  "path": "/path/to/aardvark_nm_host.py",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://.../"
  ]
}

1条回答
放荡不羁爱自由
2楼-- · 2019-01-29 11:07

The solution to the problem was to use callbacks.

I thought I would have to deal with Promises, which I did a lot of work on ... only to find there was a much easier answer.

Much easier.

查看更多
登录 后发表回答