UNPKG

@beetcb/cea

Version:

campusphere-elegant-auth: login to swms/campusphere at ease

28 lines (26 loc) 18.7 kB
#!/usr/bin/env node parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c<t.length;c++)try{f(t[c])}catch(e){i||(i=e)}if(t.length){var l=f(t[t.length-1]);"object"==typeof exports&&"undefined"!=typeof module?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):n&&(this[n]=l)}if(parcelRequire=f,i)throw i;return f}({"vwIT":[function(require,module,exports) { const{Signale:e}=require("signale"),l={types:{error:{label:"失败"},success:{label:"成功"},warn:{label:"警示"}}};module.exports=new e(l); },{}],"yJEI":[function(require,module,exports) { const{createWorker:t}=require("tesseract.js"),e=require("node-fetch"),a=require("fs"),i="/tmp/eng.traineddata.gz";async function n(){if(process.env.TESSDATA_PREFIX="/tmp",a.existsSync("/tmp")){if(a.existsSync(i))return}else a.mkdirSync("/tmp");await r("https://beetcb.gitee.io/filetransfer/tmp/eng.traineddata.gz",i)}async function r(t,i){const n=a.createWriteStream(i),r=await e(t);return await new Promise((t,e)=>{r.body.pipe(n),r.body.on("error",e),n.on("close",()=>t(`Downloaded tess data as ${i}`))})}async function s(e){await n();const a=t({langPath:"/tmp",cachePath:"/tmp"});await a.load(),await a.loadLanguage("eng"),await a.initialize("eng"),await a.setParameters({tessedit_char_whitelist:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"});const{data:{text:i}}=await a.recognize(e);return await a.terminate(),i}module.exports=s; },{}],"GFoq":[function(require,module,exports) { exports.cookieParse=((t,o)=>{const r=o.raw()["set-cookie"],n=new Map;if(!r)return n;let[s,c]=[null,[]];for(e of r){const[o,r,i]=e.match(/(.*);(?:\s?)path=((\w+|\/)*)/i);if(!r)continue;const[u,p]=r.split("="),$=`${t}::${i}`;s!==$&&s&&(n.set(s,c),c=[]),s=$,c.push([u,p])}return c.length&&n.set(s,c),n}),exports.cookieStr=((e,t,o)=>{const r=`${e}::${t}`,n=o.get(r);if(n)return n.reduce((e,t)=>{const[o,r]=t;return e+`${o}=${r}; `},"")}); },{}],"kL41":[function(require,module,exports) { const e=require("node-fetch"),{cookieParse:t,cookieStr:o}=require("./cookie");exports.Fetchh=class{constructor(e){this.headers=e,this.cookieMap=null,this.redirectUrl=null}async get(e,t={}){return await this.fetch(e,t)}async post(e,t){return t.isPost=!0,await this.fetch(e,t)}async follow(e={}){return new Promise((t,o)=>this.redirectUrl?t(this.fetch(this.redirectUrl,e)):o({status:555}))}async fetch(i,s){const{host:r,origin:c}=new URL(i),{type:a,body:h,cookiePath:n}=s,{headers:p}=this;p.origin=c,p.referer=c,p.host=r,p.cookie=this.cookieMap?o(r,n,this.cookieMap):"",p["Content-Type"]="form"===a?"application/x-www-form-urlencoded":"application/json",!a&&p["Content-Type"]&&delete p["Content-Type"];const d=await e(i,{headers:p,method:a?"POST":void 0,body:h,redirect:"manual"}).catch(e=>console.error(e));return this.redirectUrl=d.headers.get("location")||this.redirectUrl,this.updateMap(t(r,d.headers)),d}getCookieObj(){let e={};for(const[t,o]of this.cookieMap.entries()){const[i,s,r]=t.match(/(.*)(::.*)/);e[`${s.includes("campusphere")?"campusphere":"swms"}${r}`]=o.reduce((e,t)=>`${e}${t.join("=")}; `,"")}return e}updateMap(e){if(this.cookieMap)for(const[t,o]of e.entries()){const e=this.cookieMap?this.cookieMap.get(t):[];e?this.cookieMap.set(t,[...e,...o]):this.cookieMap.set(t,o)}else this.cookieMap=e}}; },{"./cookie":"GFoq"}],"b6gf":[function(require,module,exports) { const e={"宁波大学":{formIdx:0,rememberMe:"on",cookiePath:"/",checkCaptchaPath:"/needCaptcha.html",getCaptchaPath:"/captcha.html"}},t={rememberMe:!0,getCaptchaPath:"/getCaptcha.htl",checkCaptchaPath:"/checkNeedCaptcha.htl",cookiePath:"/authserver",formIdx:2,pwdEncrypt:!0},a={lt:"/security/lt",rememberMe:!0,checkCaptchaPath:"/checkNeedCaptcha",getCaptchaPath:"/generateCaptcha"};module.exports=((h,c)=>h?new Proxy(e[h]||{},{get:(e,h,p)=>void 0===e[h]?c?a[h]:t[h]:Reflect.get(e,h,p)}):{}); },{}],"qJqB":[function(require,module,exports) { function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,a)}return r}function t(t){for(var a=1;a<arguments.length;a++){var s=null!=arguments[a]?arguments[a]:{};a%2?e(Object(s),!0).forEach(function(e){r(t,e,s[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(s)):e(Object(s)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(s,e))})}return t}function r(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const a=require("cheerio"),s=require("crypto"),i=require("./captcha"),n=require("../utils/logger"),{Fetchh:o}=require("./utils/fetchh");module.exports=(async(e,r)=>{const s=require("./school-edge-cases")(e.name,e.casOrigin.includes("iap")),l={"Cache-Control":"max-age=0","Accept-Encoding":"gzip, deflate","Upgrade-Insecure-Requests":"1","User-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"},u=new o(l),p=r.alias,{cookiePath:f}=s;res=await u.get(e.login),res=await u.follow();const h={};let g=null;if(void 0!==s.formIdx){const e=await res.text(),t=a.load(e),r=t("form[method=post]").get(s.formIdx),i=t("input[type=hidden]",r);i.each(e=>{const t=i[e],[r,a]=[t.attribs.name,t.attribs.value];r&&a?h[r]=a:a&&(g=a)})}else{l.Referer=res.headers.get("location");const t=new URL(l.Referer).search;if(0===Object.keys(h).length){res=await u(`${e.casOrigin}${s.lt}${t}`);const{result:r}=await res.json();Object.defineProperties(h,{lt:{value:r._lt,enumerable:!0},needCaptcha:{value:r.needCapt,enumerable:!0},dllt:{value:"",enumerable:!0},iap:{value:!0,enumerable:!0}})}}const m=new URLSearchParams(t(t({username:r.username,password:g?new c(r.password,g).encrypt():r.password},h),{},{rememberMe:s.rememberMe})),d=`?username=${r.username}&ltId=${h.lt}`;if(void 0===h.needCaptcha?(await(await u.get(`${e.casOrigin}${s.checkCaptchaPath}${d}`,{cookiePath:f})).text()).includes("true"):h.needCaptcha){n.warn({message:"登录需要验证码,正在用 OCR 识别",suffix:`@${p}`});const t=(await i(`${e.casOrigin}${s.getCaptchaPath}${d}`)).replace(/\s/g,"");if(!(t.length>=4))return void n.error({message:`验证码识别失败,长度${t.length}错误`,suffix:`@${p}`});n.success({message:`使用验证码 ${t} 登录`,suffix:`@${p}`}),m.append("captcha",t)}res=await u.follow({type:"form",body:m.toString(),cookiePath:f});const b=res.headers.get("location");if(b)if(b.includes(".do"))n.error({message:"登录失败,密码安全等级低,需要修改",suffix:`@${p}`});else{if(res=await u.follow({cookiePath:f}),res=await u.follow({cookiePath:f}),/30(1|2|7|8)/.test(res.status+""))return n.success({message:"登录成功",suffix:`@${p}`}),u.getCookieObj();n.error({message:`登录失败,${res.statusText}`,suffix:`@${p}`})}else n.error({message:`登录失败,${res.statusText}`,suffix:`@${p}`})});class c{constructor(e,t){this.pwd=e,this.key=t}encrypt(){const{key:e,pwd:t}=this,r=(0,this.randomString)(64)+t,a=Buffer.alloc(16,0),i=s.createCipheriv("aes-128-cbc",e,a);let n=i.update(r,"utf8","base64");return n+=i.final("base64")}randomString(e){return Array(e).fill(null).reduce((e="")=>e+="ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678".charAt(Math.floor(48*Math.random())),"")}} },{"./captcha":"yJEI","../utils/logger":"vwIT","./utils/fetchh":"kL41","./school-edge-cases":"b6gf"}],"RVdT":[function(require,module,exports) { const e=require("node-fetch"),s=require("crypto"),i=require("../utils/logger"),{v1:t}=require("uuid");class n{constructor(e){this.signApi={list:`${e.origin}/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay`,detail:`${e.origin}/wec-counselor-sign-apps/stu/sign/detailSignInstance`,sign:`${e.origin}/wec-counselor-sign-apps/stu/sign/submitSign`,home:`${e.origin}/wec-counselor-sign-apps/stu/mobile`}}}exports.signApp=class extends n{constructor(e,s){super(e),this.headers={"user-agent":"Mozilla/5.0 (Linux; Android 10; GM1910 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.101 Mobile Safari/537.36 cpdaily/8.2.13 wisedu/8.2.13","content-type":"application/json"},this.addr=e.addr,this.id=s.username,process.env[s.username]=s}async signInfo(s){process.env[this.id];if(!s)return!0;this.headers.cookie=s["campusphere::/"];const{signApi:i,headers:t}=this,n=await e(i.list,{method:"POST",headers:t,body:JSON.stringify({})});if(!n.headers.get("content-type").includes("application/json"))return!0;const r=await n.json();if("SUCCESS"===r.message){const e=r.datas;return this.curTask=e.unSignedTasks[0]||e.leaveTasks[0],!1}return!0}async signWithForm(){if(!this.curTask)return void(this.result={"签到结果":"今日签到任务已完成或COOKIE无效,取消签到"});const{signApi:s,headers:i}=this,{curTask:{signInstanceWid:t,signWid:n}}=this;let r=await e(s.detail,{headers:i,method:"POST",body:JSON.stringify({signInstanceWid:t,signWid:n})});const a=await r.json();let{extraField:o,longitude:d,latitude:l,signPlaceSelected:c,isNeedExtra:u,signedStuInfo:g}=a.datas;const p=c,h=process.env[this.id].addr;[d,l]=h?this.signAtHomePos():this.locale(p[0]);const m={signInstanceWid:t,longitude:d,latitude:l,isNeedExtra:u,extraFieldItems:this.fillExtra(o),isMalposition:h?1:0,abnormalReason:"",signPhotoUrl:"",position:this.addr,uaIsCpadaily:!0,signVersion:"1.0.0"};i["Cpdaily-Extension"]=this.extention(m),r=await e(s.sign,{headers:i,method:"POST",body:JSON.stringify(m)});const f={"签到结果":(r=await r.json()).message,"签到地址":m.position,"真实信息":g.userName};process.env.GITHUB_ACTION&&(delete f["签到地址"],delete f["真实信息"]),this.result=f}signAtHomePos(){const e=process.env[this.id].addr,s=e instanceof Array?[e]:[["116.622631","40.204822","北京市顺义区X012"],["115.825701","32.914915","安徽省阜阳市颍泉区胜利北路79"],["119.292590","26.164789","福建省福州市晋安区"],["103.836093","36.068012","甘肃省兰州市城关区南滨河东路709"],["108.360128","22.883516","广西壮族自治区南宁市兴宁区"],["113.391549","22.590350","广东省中山市兴港中路172号"],["111.292396","30.718343","湖北省宜昌市西陵区珍珠路32号"],["118.793117","32.074771","江苏省南京市玄武区昆仑路8号"]],i=Math.floor(Math.random()*s.length);return this.addr=s[i][2],this.locale({longitude:s[i][0]+"",latitude:s[i][1]+""})}locale({longitude:e,latitude:s}){return[e.slice(0,10),s.slice(0,9)].map(e=>("0"===e[e.length-1]&&(e=e.replace(/\d{1}$/,"1")),Number(e)))}fillExtra(e){return e.map(e=>{let s;const i=e.extraFieldItems.filter(e=>(!1===e.isAbnormal&&(s=e.wid),!e.isAbnormal))[0];return{extraFieldItemWid:s,extraFieldItemValue:i.content}})}extention(e){const s={lon:e.longitude.toString(),model:"Cock",appVersion:"8.2.14",systemVersion:"4.4.4",userId:process.env[this.id].username,systemName:"android",lat:e.latitude.toString(),deviceId:t()};return this.encrypt(s)}encrypt(e){const i=Buffer.from([1,2,3,4,5,6,7,8]),t=s.createCipheriv("des-cbc","b3L26XNL",i);let n=t.update(JSON.stringify(e),"utf8","base64");return n+=t.final("base64")}decrypt(){const e=Buffer.from([1,2,3,4,5,6,7,8]),i=s.createDecipheriv("des-cbc","b3L26XNL",e);let t=i.update("long base 64","base64","utf8");t+=i.final("utf8")}}; },{"../utils/logger":"vwIT"}],"waFA":[function(require,module,exports) { const s=require("@beetcb/sstore"),e=require("./utils/logger"),a=require("./crawler/casLogIn"),{signApp:t}=require("./campusphere/app");async function i(i,o){let c=s.get(o);const n=i.alias;c||(c=await a(s.get("school"),i))&&(s.set(o,c),e.success({message:"已成功获取并缓存 COOKIE",suffix:`@${n}`}));const r=new t(s.get("school"),i);return await r.signInfo(c)?(c=await a(s.get("school"),i))&&(s.set(o,c),await r.signInfo(c),e.success({message:"已成功刷新并缓存 COOKIE",suffix:`@${n}`})):e.success({message:"尝试使用缓存中的 COOKIE",suffix:`@${n}`}),r}s.handleCookie=(async()=>{const e=[];return await Promise.all(s.get("users").map(async s=>{const a=`cookie.${s.alias}`;s.sign=await i(s,a),e.push(s)})),e}),module.exports=s; },{"./utils/logger":"vwIT","./crawler/casLogIn":"qJqB","./campusphere/app":"RVdT"}],"LVu9":[function(require,module,exports) { const s=require("./cookie"),e=require("./utils/logger"),a=require("fs"),t=require("node-fetch"),{prompt:o}=require("inquirer"),n=require("@iarna/toml/parse-string");function r(s){if(a.existsSync(s)){const e=n(a.readFileSync(s,"utf8"));if(e)return e}}s.init=async function(){const s=process.env,a=r("./conf.toml"),t=new i,o=new c;if(s.users&&s.school){e.warn({message:"尝试从环境变量加载配置"});const a=t.loadUserFromEnv(s);await o.loadSchoolFromEnv(s,a)}else a&&(e.warn({message:"尝试从配置文件加载配置"}),t.loadUserFromToml(a),await o.loadSchoolFromToml(a))};class i{constructor(){this.initConf(),this.selectType=null}initConf(){s.get("users")||s.set("users",[])}storeUsers(e){const a=s.get("users"),t=a.map(s=>s.alias);e=e?e.filter(s=>!t.includes(s.alias)):[],s.set("users",[...e,...a])}loadUserFromToml(s){this.storeUsers(s.users),e.success({message:`用户${s.users.reduce((s,e)=>`${s}${e.alias} `," ")}已加载`})}loadUserFromEnv({users:s}){if(s){const a=s.split("\n").map(s=>{const[e,a,t]=s.split(" ");let o=s.split("home ")[1];return{username:e,password:a,alias:t,addr:o=o?o.split(" "):null}});return this.storeUsers(a),e.warn(`用户${a.reduce((s,e)=>`${s}${e.alias} `," ")}已加载`),a}}async load(){const e=[{type:"list",name:"type",message:`用户编辑: ${s.get("school")?" 学校信息已成功配置":" 学校信息未配置"}\n 已有用户:${s.get("users").reduce((s,e)=>{return s+" "+e.alias},"")}`,choices:[{value:1,name:"添加用户"},{value:2,name:"删除用户"},{value:-1,name:"取消"}]}],a=await o(e);this.selectType=a.type}async createUser(){const a=await o([{type:"input",name:"username",message:"请输入用户名"},{type:"input",name:"password",message:"请输入密码"},{type:"input",name:"alias",message:"(可选)请输入用户别名"}]);if(s.get("users").some(s=>s.alias===a.alias))e.error("🙃 用户已存在");else{const t={username:a.username,password:a.password,alias:a.alias||a.username};s.set("users",[t,...s.get("users")]),e.success("🎉 成功添加用户",t)}}async deleteUser(){const a=[{type:"list",name:"selection",message:"请选择删除对象:",choices:[...s.get("users").map((s,e)=>({value:e,name:`${s.alias||s.user.name}`})),{value:-1,name:"取消"}]}],t=await o(a),n=s.get("users").filter((s,e)=>e!==t.selection);s.set("users",n),e.success("🎉 成功删除用户")}}class c{async init(){if(s.get("school"))e.warn({message:"学校信息已配置"});else{const a=[{type:"input",name:"ids",message:"学校的英文简称(推荐,部分学校支持)\n请参阅 https://github.com/beetcb/cea#abbrlist 自行判断\n或中文全称(备用选项,所有学校均支持):"}];let t=await o(a);const n=await this.schoolApi(t.ids);n.addr=await this.schoolAddr(n.name),s.set("school",n),e.success({message:`你的学校 ${n.name} 已完成设定`})}}async loadSchoolFromToml(a){if(!s.get("school")){const t=await this.schoolApi(a.school);a.users.some(s=>""===s.addr)&&(t.addr=await this.schoolAddr(t.name)),s.set("school",t),e.success({message:`你的学校 ${t.name} 已完成设定`})}}async loadSchoolFromEnv({school:a},t){if(s.get("school"))e.warn({message:"学校信息已配置"});else{const o=await this.schoolApi(a);t.some(s=>""===s.addr)&&(o.addr=await this.schoolAddr(o.name)),s.set("school",o),e.success({message:`你的学校 ${o.name} 已完成设定`})}}async schoolAddr(s){let e=await t(`https://api.map.baidu.com/?qt=s&wd=${encodeURIComponent(s)}&ak=E4805d16520de693a3fe707cdc962045&rn=10&ie=utf-8&oue=1&fromproduct=jsapi&res=api`);e=await e.json();const{addr:a}=e.content[0];return a}async schoolApi(s){let a,o;s.match(/\w+/)?o=s:(a=await t("https://mobile.campushoy.com/v6/config/guest/tenant/list").catch(s=>s),o=(await a.json()).data.find(e=>e.name===s).id),a=await t(`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${o}`).catch(s=>s);const n=(a=await JSON.parse(await a.text())).data[0].name;let r=new URL(a.data[0].ampUrl).origin,i=a.data[0].idsUrl;return r.includes("campusphere")||(r=new URL(a.data[0].ampUrl2).origin),process.env.GITHUB_ACTION&&"whpu"===s&&(i="http://whpu.beetcb.com/authserver",e.warn({message:`使用代理访问${n}`})),{name:n,casOrigin:i,origin:r,login:`${r}/iap/login?service=${encodeURIComponent(`${r}/portal/login`)}`,campusphere:`${r}/portal/login`}}}module.exports={conf:s,User:i,School:c}; },{"./cookie":"waFA","./utils/logger":"vwIT"}],"Focm":[function(require,module,exports) { module.exports=require("./api").conf; },{"./api":"LVu9"}],"PTk1":[function(require,module,exports) { const a=require("../src/index");async function i(i){const n={};return await Promise.all(i.map(async a=>{await a.sign.signWithForm(),n[a.alias||a.id]=a.sign.result})),a.close(),n}(async()=>{const n=await a.handleCookie(),s=await i(n);console.table(s)})(); },{"../src/index":"Focm"}],"LM5A":[function(require,module,exports) { const{User:e,School:a,conf:o}=require("./api");(async()=>{const s=process.argv[2]||"",c=process.argv[3];switch(s){case"-h":case"--help":console.log("\nUsage: cea <command>\n\nAll Commands: \n user create|delete user\n school config your school info\n sign campusphere check in\n load load config info from toml file\n rm remove stored config feilds\n");break;case"user":{const a=new e(o);await a.load();const s=a.selectType;1===s&&await a.createUser(),2===s&&await a.deleteUser();break}case"school":await new a(o).init();break;case"rm":"all"===c&&o.clear(),o.del(c);break;case"sign":require("../TEST/dcampus");break;case"load":o.clear(),await o.init()}o.close()})(),module.exports={User:e,School:a}; },{"./api":"LVu9","../TEST/dcampus":"PTk1"}]},{},["LM5A"], null)