| 1 | // PLUGIN_INFO//{{{ |
|---|
| 2 | var PLUGIN_INFO = |
|---|
| 3 | <VimperatorPlugin> |
|---|
| 4 | <name>{NAME}</name> |
|---|
| 5 | <description>login manager</description> |
|---|
| 6 | <author mail="konbu.komuro@gmail.com" homepage="http://d.hatena.ne.jp/hogelog/">hogelog</author> |
|---|
| 7 | <version>0.0.4</version> |
|---|
| 8 | <minVersion>2.0pre</minVersion> |
|---|
| 9 | <maxVersion>2.2pre</maxVersion> |
|---|
| 10 | <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/loginManger.js</updateURL> |
|---|
| 11 | <license>public domain</license> |
|---|
| 12 | <detail><![CDATA[ |
|---|
| 13 | |
|---|
| 14 | === TODO === |
|---|
| 15 | |
|---|
| 16 | ]]></detail> |
|---|
| 17 | </VimperatorPlugin>; |
|---|
| 18 | //}}} |
|---|
| 19 | |
|---|
| 20 | (function(){ |
|---|
| 21 | |
|---|
| 22 | var loginManager = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); |
|---|
| 23 | |
|---|
| 24 | var services = { |
|---|
| 25 | pixiv: { |
|---|
| 26 | HOST: ["http://www.pixiv.net"], |
|---|
| 27 | LOGIN: "/index.php", |
|---|
| 28 | LOGOUT: "/logout.php", |
|---|
| 29 | usernameField: "pixiv_id", |
|---|
| 30 | passwordField: "pass", |
|---|
| 31 | extraField: { |
|---|
| 32 | mode: "login", |
|---|
| 33 | skip: "1", |
|---|
| 34 | }, |
|---|
| 35 | }, |
|---|
| 36 | drawr: { |
|---|
| 37 | HOST: ["http://drawr.net"], |
|---|
| 38 | LOGIN: "/login.php", |
|---|
| 39 | LOGOUT: "/logout.php", |
|---|
| 40 | usernameField: "user_uid", |
|---|
| 41 | passwordField: "user_upw", |
|---|
| 42 | extraField: { |
|---|
| 43 | mode: "autologin", |
|---|
| 44 | }, |
|---|
| 45 | }, |
|---|
| 46 | mixi: { |
|---|
| 47 | HOST: ["https://mixi.jp", "http://mixi.jp"], |
|---|
| 48 | LOGIN: "/login.pl", |
|---|
| 49 | LOGOUT: "/logout.pl", |
|---|
| 50 | usernameField: "email", |
|---|
| 51 | passwordField: "password", |
|---|
| 52 | extraField: { |
|---|
| 53 | next_url: "/home.pl", |
|---|
| 54 | }, |
|---|
| 55 | }, |
|---|
| 56 | hatena: { |
|---|
| 57 | HOST: ["https://www.hatena.ne.jp", "http://www.hatena.ne.jp"], |
|---|
| 58 | LOGIN: "/login", |
|---|
| 59 | LOGOUT: "/logout", |
|---|
| 60 | usernameField: "name", |
|---|
| 61 | passwordField: "password", |
|---|
| 62 | logoutBeforeLogin: true, |
|---|
| 63 | }, |
|---|
| 64 | hatelabo: { |
|---|
| 65 | HOST: ["https://www.hatelabo.jp", "http://www.hatelabo.jp"], |
|---|
| 66 | LOGIN: "/login", |
|---|
| 67 | LOGOUT: "/logout", |
|---|
| 68 | usernameField: "key", |
|---|
| 69 | passwordField: "password", |
|---|
| 70 | logoutBeforeLogin: true, |
|---|
| 71 | extraField: { |
|---|
| 72 | mode: "enter", |
|---|
| 73 | }, |
|---|
| 74 | }, |
|---|
| 75 | tumblr: { |
|---|
| 76 | HOST: ["http://www.tumblr.com"], |
|---|
| 77 | LOGIN: "/login", |
|---|
| 78 | LOGOUT: "/logout", |
|---|
| 79 | usernameField: "email", |
|---|
| 80 | passwordField: "password", |
|---|
| 81 | }, |
|---|
| 82 | twitter: { |
|---|
| 83 | HOST: ["https://twitter.com", "http://twitter.com"], |
|---|
| 84 | LOGIN: "/sessions", |
|---|
| 85 | LOGOUT: "/sessions/destroy", |
|---|
| 86 | usernameField: "session[username_or_email]", |
|---|
| 87 | passwordField: "session[password]", |
|---|
| 88 | extraField: { |
|---|
| 89 | authenticity_token: tokenGetter(/authenticity_token.+value="(.+?)"/), |
|---|
| 90 | }, |
|---|
| 91 | }, |
|---|
| 92 | "wassr.com": { |
|---|
| 93 | HOST: ["https://wassr.com", "http://wassr.com", "https://wassr.jp", "http://wassr.jp"], |
|---|
| 94 | LOGIN: "/account/login", |
|---|
| 95 | LOGOUT: "/account/logout", |
|---|
| 96 | usernameField: "login_id", |
|---|
| 97 | passwordField: "login_pw", |
|---|
| 98 | extraField: { |
|---|
| 99 | CSRFPROTECT: tokenGetter(/CSRFPROTECT.+value="(.+?)"/), |
|---|
| 100 | }, |
|---|
| 101 | }, |
|---|
| 102 | "wassr.jp": { |
|---|
| 103 | HOST: ["https://wassr.jp", "http://wassr.jp", "https://wassr.com", "http://wassr.com"], |
|---|
| 104 | LOGIN: "/account/login", |
|---|
| 105 | LOGOUT: "/account/logout", |
|---|
| 106 | usernameField: "login_id", |
|---|
| 107 | passwordField: "login_pw", |
|---|
| 108 | extraField: { |
|---|
| 109 | CSRFPROTECT: tokenGetter(/CSRFPROTECT.+value="(.+?)"/), |
|---|
| 110 | }, |
|---|
| 111 | }, |
|---|
| 112 | }; |
|---|
| 113 | for (name in services){ |
|---|
| 114 | services[name] = new Service(services[name]); |
|---|
| 115 | } |
|---|
| 116 | if (liberator.globalVariables.userLoginServices) { |
|---|
| 117 | let userServices = liberator.globalVariables.userLoginServices; |
|---|
| 118 | for (name in userServices){ |
|---|
| 119 | services[name] = new Service(userServices[name]); |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | // Library |
|---|
| 124 | function Service(service) //{{{ |
|---|
| 125 | { |
|---|
| 126 | let self = this; |
|---|
| 127 | self.login = function(username){ |
|---|
| 128 | let content = {}; |
|---|
| 129 | let host = service.HOST[0]; |
|---|
| 130 | content[service.usernameField] = username; |
|---|
| 131 | if (!self.setPassword(content, username)) { |
|---|
| 132 | liberator.echoerr('failed get password "'+host+'" as '+username); |
|---|
| 133 | return false; |
|---|
| 134 | } |
|---|
| 135 | if (service.extraField && !self.setExtraField(content)) return false; |
|---|
| 136 | |
|---|
| 137 | let loginURL = host+service.LOGIN; |
|---|
| 138 | let error = function(e) liberator.echo('login failed "'+host+'" as '+username); |
|---|
| 139 | let success = function(e) liberator.echo('login "'+host+'" as '+username); |
|---|
| 140 | let login = function() request(loginURL, content, success, error); |
|---|
| 141 | if (service.logoutBeforeLogin) { |
|---|
| 142 | let logoutURL = host+service.LOGOUT; |
|---|
| 143 | return request(logoutURL, content, login, error); |
|---|
| 144 | } |
|---|
| 145 | |
|---|
| 146 | login(); |
|---|
| 147 | }; |
|---|
| 148 | self.logout = function(){ |
|---|
| 149 | let content = {}; |
|---|
| 150 | let host = service.HOST[0]; |
|---|
| 151 | if (service.extraField && !self.setExtraField(content)) return false; |
|---|
| 152 | let logoutURL = host+service.LOGOUT; |
|---|
| 153 | let error = function() liberator.echo('logout failed "'+host+'" as '+username); |
|---|
| 154 | let success = function() liberator.echo('logout "'+host+'" as '+username); |
|---|
| 155 | request(logoutURL, content, success, error); |
|---|
| 156 | }; |
|---|
| 157 | self.getLogins = function() { |
|---|
| 158 | return [loginManager.findLogins({}, host, host, null) for each(host in service.HOST)] |
|---|
| 159 | .reduce(function(sum, logins){ |
|---|
| 160 | return sum.concat(logins.filter(function(login) |
|---|
| 161 | sum.length==0 || sum.filter(function(x) |
|---|
| 162 | x.username==login.username).length==0)) |
|---|
| 163 | }, []); |
|---|
| 164 | }; |
|---|
| 165 | self.getUsernames = function(){ |
|---|
| 166 | return [x.username for each(x in self.getLogins()) if(x.username)]; |
|---|
| 167 | }; |
|---|
| 168 | self.setPassword = function(content, username){ |
|---|
| 169 | let logins = self.getLogins() |
|---|
| 170 | .filter(function(x) x.username==username); |
|---|
| 171 | |
|---|
| 172 | if(logins.length==0) return false; |
|---|
| 173 | content[service.passwordField] = logins[0].password; |
|---|
| 174 | return content; |
|---|
| 175 | }; |
|---|
| 176 | self.setExtraField = function(content){ |
|---|
| 177 | if (!service.extraField) return false; |
|---|
| 178 | for (field in service.extraField){ |
|---|
| 179 | value = service.extraField[field]; |
|---|
| 180 | switch(typeof value) { |
|---|
| 181 | case "function": |
|---|
| 182 | content[field] = value(service); |
|---|
| 183 | break; |
|---|
| 184 | case "string": |
|---|
| 185 | content[field] = value; |
|---|
| 186 | break; |
|---|
| 187 | } |
|---|
| 188 | if (!content[field]){ |
|---|
| 189 | liberator.echoerr("failed get "+field); |
|---|
| 190 | return false; |
|---|
| 191 | } |
|---|
| 192 | } |
|---|
| 193 | return content; |
|---|
| 194 | }; |
|---|
| 195 | for (prop in service){ |
|---|
| 196 | if (self[prop]) self["_"+prop] = self[prop]; |
|---|
| 197 | self[prop] = service[prop]; |
|---|
| 198 | } |
|---|
| 199 | } //}}} |
|---|
| 200 | |
|---|
| 201 | function encode(content) |
|---|
| 202 | [k+"="+encodeURIComponent(content[k]) for(k in content)].join("&"); |
|---|
| 203 | function request(url, content, onload, onerror) |
|---|
| 204 | { |
|---|
| 205 | let req = new XMLHttpRequest; |
|---|
| 206 | req.open("POST", url, true); |
|---|
| 207 | req.onload = onload; |
|---|
| 208 | req.onerror = onerror; |
|---|
| 209 | req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); |
|---|
| 210 | req.send(encode(content)); |
|---|
| 211 | } |
|---|
| 212 | function tokenGetter(pattern) //{{{ |
|---|
| 213 | { |
|---|
| 214 | return function(service){ |
|---|
| 215 | let res = util.httpGet(service.HOST[0]); |
|---|
| 216 | if (pattern.test(res.responseText)){ |
|---|
| 217 | return RegExp.$1; |
|---|
| 218 | } |
|---|
| 219 | }; |
|---|
| 220 | } //}}} |
|---|
| 221 | |
|---|
| 222 | // Commands |
|---|
| 223 | // {{{ |
|---|
| 224 | commands.addUserCommand(["login"], "Login", |
|---|
| 225 | function(args){ |
|---|
| 226 | let [servicename, username] = args; |
|---|
| 227 | let service = services[servicename]; |
|---|
| 228 | if (!service) return false; |
|---|
| 229 | service.login(username); |
|---|
| 230 | }, { |
|---|
| 231 | completer: function(context, args){ |
|---|
| 232 | if (args.completeArg == 0){ |
|---|
| 233 | context.title = ["service"]; |
|---|
| 234 | context.completions = [[s,""] for(s in services)]; |
|---|
| 235 | } else if (args.completeArg == 1){ |
|---|
| 236 | let service = services[args[0]]; |
|---|
| 237 | if (!service) return false; |
|---|
| 238 | context.title = ["username"]; |
|---|
| 239 | context.completions = [[u,""] for each(u in service.getUsernames())]; |
|---|
| 240 | } |
|---|
| 241 | }, |
|---|
| 242 | literal: 1, |
|---|
| 243 | }); |
|---|
| 244 | commands.addUserCommand(["logout"], "Logout", |
|---|
| 245 | function(args){ |
|---|
| 246 | let [servicename, username] = args; |
|---|
| 247 | let service = services[servicename]; |
|---|
| 248 | if (!service) return false; |
|---|
| 249 | service.logout(username); |
|---|
| 250 | }, { |
|---|
| 251 | completer: function(context, args){ |
|---|
| 252 | context.title = ["service"]; |
|---|
| 253 | context.completions = [[s,""] for(s in services)]; |
|---|
| 254 | }, |
|---|
| 255 | }); |
|---|
| 256 | // }}} |
|---|
| 257 | |
|---|
| 258 | })(); |
|---|
| 259 | // vim: fdm=marker sw=4 ts=4 et: |
|---|