问题
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:
- A Credentials Server (CS) is started up with encrypted credential tokens
- Selenium opens the browser with custom extension
- The extension is triggered onAuthRequired
- The Native Messaging Host (NMH) starts then receives a 'ready' message
- The NMH uses a simple protocol to request tokens from the CS
- The NMH decrypts the tokens
- The NMH passes the credentials to background.js
- background.js returns the credentials to chrome
- 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:
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.
来源:https://stackoverflow.com/questions/47564226/javascript-syncronicity-combining-onauthrequired-listener-and-native-massaging