본문

Zotero Connector 원격 컴퓨터에서 접속하기

회사에서 사용하는 수많은 문서들, 그리고 (Evernote에서 관리하던) 개인적인 자료들을 Zotero로 편리하게 관리하고 있다. 이를 위해 Add-on들도 직접 만들어서 사용중인데 이거 없으면 어떻게 살까 싶을 정도이다. 위 스크린샷은 지금 만들고있는, 문서간 관계를 보여주는 addon인데 아직 완성이 안되어서 공개를 못하고 있다.

 

한가지 아쉬운것은 회사 인트라넷에 접속해서 Zotero Connector를 사용하여 웹페이지 또는 문서 스크랩을 하는일이 종종 있는데, 회사 컴퓨터가 아니면 인트라넷에 접속이 안되기 때문에 항상 회사 컴퓨터를 켜야 한다는것이다. (그동안 돈을내고 우회해왔지만 가성비가 떨어졌다) 아직까지도 재택근무를 하고있기 떄문에 집컴퓨터로만 작업하고싶은 마음이 컸고 이를 해결하고자 하였고 그 여정을 아래에 정리해본다.

 

1. 문제점

Zotero의 환경설정 extensions.zotero.httpServer.port 에 23119가 기본 포트로 설정되어있으며 Zotero Connector의 환경설정 connector.url에 http://127.0.0.1:23119/ 가 기본으로 설정되어있다. 따라서 처음생각은 Zotero Connector에서 127.0.0.1 이부분만 집컴퓨터 ip로 변경하면 될 줄 알았다.

 

하지만 인트라넷 내부에서 외부로 http 접근을 할때는 80포트일 경우에만 패킷이 허용되고 이외의 포트를 사용할때는 패킷이 전송되지 않는다는 것을 알게되었다. (애꿎은 집 공유기 설정만 열심히 들여다봤다..) 따라서 Connector의 url 설정은 http://집컴ip:80/ 이런식으로 설정해야만 했다.

 

문제는 또 있었다. Zotero의 서버 코드인 zotero/chrome/content/zotero/xpcom/server.js 에는 아래와 같은 init 코드가 있는데 다른부분에서 호출할때 bindAllAddr 변수를 설정해서 init하는 경우는 없었다. 즉, 항상 127.0.0.1 local 주소에 바인딩 하기 때문에 외부 주소에 대해서는 listen하지 않아 현재 Zotero가 동작하는 컴퓨터에서만 Connector를 사용할 수 있다. 

 

2. 포트포워딩 사용 (실패)

위의 소스에서 예상할 수 있듯, netstat -ano 명령을 실행하면 아래와 같이 출력이 된다.

 

============

프로토콜  로컬 주소              외부 주소              상태            PID

TCP    127.0.0.1:23119        0.0.0.0:0              LISTENING       16960

============

 

외부에서 오는 패킷을 loopback 주소로 전달해 해주기 위하여 아래와 같이 실행할 수 있다. show all 하면 내역이 뜬다.

netsh interface portproxy add v4tov4 listenport=80 listenaddress=* connectport=23119 connectaddress=127.0.0.1
netsh interface portproxy delete v4tov4 listenport=80 listenaddress=*
netsh interface portproxy show all

 

============

ipv4 수신 대기:             ipv4에 연결:

주소            포트        주소            포트
--------------- ----------  --------------- ----------
*               80          127.0.0.1       23119

============

 

하지만 이때 문제는 Zotero Connector는 http 메시지를 사용한다는것. GET/POST 메시지에서 host 주소가 들어가는데 그부분이 변경되지 않았기 떄문에 "HTTP/1.0 400 Bad Request X-Zotero-Version: 6.0.7 X-Zotero-Connector-API-Version: 2 Content-Type: text/plain Invalid Host header" 메시지가 뜬다. 

 

3. Http forwarding (성공)

Http proxy를 써야하나.. 하다가 그냥 http header만 간단하게 바꾸면 되는거지 싶어서 인터넷에 코드가 있을까 잠깐 검색해보니 역시나 있었다. "The simplest HTTP proxy with custom headers" Nodejs로 되어있는 코드인데 30줄도 안되는 짧은 코드라서 아주 맘에 들었다.

 

나같은 경우는 원 페이지에서 아래와 같이 약간만 수정해주었다. 80포트를 사용하게 하였고, 워낙에 자주쓰이는 80포트라 공격이 들어올수 있으니 주소에 'connector' 문자열이 없으면 그냥 응답을 안해주는 부분, host 부분을 고쳐주는 부분만 고쳤다. 그랬더니 원격에서도 이제 Zotero Connector를 사용할 수 있다.

const http = require('http');

function onRequest(req, res) {
  console.log('serve: ' + req.url);
  if (req.url.indexOf('connector')==-1) return false;
  const options = {
    hostname: '127.0.0.1',
    port: 23119,
    path: req.url,
    method: req.method,
    headers: {
      ...req.headers,
      //'authorization': 'Basic foobar',
	  'host': '127.0.0.1:23119'
    }
  };

  const proxy = http.request(options, function (r) {
    res.writeHead(r.statusCode, r.headers);
    r.pipe(res, {
      end: true
    });
  });

  req.pipe(proxy, {
    end: true
  });
}

http.createServer(onRequest).listen(80);
console.log('Listening on port 80')

 

위 소스를 실행시키면 아래와같이 로그가 찍히며 잘 동작하는것을 확인할 수 있다.

Listening on port 80
serve: /
serve: /connector/ping
serve: /connector/saveSnapshot
serve: /connector/getSelectedCollection
serve: /favicon.ico
serve: /connector/saveSingleFile
serve: /connector/delaySync
serve: /connector/ping
serve: /connector/saveSnapshot
serve: /connector/getSelectedCollection
serve: /connector/updateSession
serve: /connector/updateSession
serve: /connector/delaySync
serve: /connector/saveSingleFile
serve: /connector/updateSession
serve: /connector/updateSession

댓글

Holic Spirit :: Tistory Edition

design by tokiidesu. powerd by kakao.