본문으로 이동
주 메뉴
주 메뉴
사이드바로 이동
숨기기
둘러보기
대문
최근 바뀜
게임 목록
임의의 게임으로
커뮤니티
리버티게임 본진
리버티게임(개발)
검색
검색
보이기
계정 만들기
로그인
개인 도구
계정 만들기
로그인
이 서버는
리버티게임
의 개발용 베타 서버로, 게임 플레이 용도로 제작된 사이트가 아닙니다.
리버티게임의 자동 인증된 사용자라면 개발에 필요한 관리자 권한을
신청
할 수 있습니다.
틀 및 기능별 소도구를 필요한 문서에만 선택적으로 로딩하는 테스트를 진행하고 있습니다. 작동하지 않는 문서가 있다면
담당자
에게 알려주세요.
미디어위키:Gadget-PluginX.js 문서 원본 보기
메시지
토론
English
읽기
원본 보기
역사 보기
도구
도구
사이드바로 이동
숨기기
동작
읽기
원본 보기
역사 보기
새로 고침
일반
여기를 가리키는 문서
가리키는 글의 최근 바뀜
특수 문서 목록
문서 정보
축약된 URL 얻기
보이기
사이드바로 이동
숨기기
←
미디어위키:Gadget-PluginX.js
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
이 문서는 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다.
이 문서는
관리자
만이 수정할 수 있습니다. 내용의 변경이 필요하다면
관리자 요청
에 편집 요청을 남겨 주세요.
모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다.
문서의 원본을 보거나 복사할 수 있습니다.
고급
특수 문자
도움말
문단 제목
2단계
3단계
4단계
5단계
형식
넣기
라틴 문자
확장 라틴 문자
IPA 문자
기호
그리스 문자
그리스어 확장
키릴 문자
아랍 문자
아랍어 확장
히브리 문자
뱅골어
타밀어
텔루구어 문자
싱할라 문자
데바나가리어
구자라트 문자
태국어
라오어
크메르어
캐나다 원주민 언어
룬 문자
Á
á
À
à
Â
â
Ä
ä
Ã
ã
Ǎ
ǎ
Ā
ā
Ă
ă
Ą
ą
Å
å
Ć
ć
Ĉ
ĉ
Ç
ç
Č
č
Ċ
ċ
Đ
đ
Ď
ď
É
é
È
è
Ê
ê
Ë
ë
Ě
ě
Ē
ē
Ĕ
ĕ
Ė
ė
Ę
ę
Ĝ
ĝ
Ģ
ģ
Ğ
ğ
Ġ
ġ
Ĥ
ĥ
Ħ
ħ
Í
í
Ì
ì
Î
î
Ï
ï
Ĩ
ĩ
Ǐ
ǐ
Ī
ī
Ĭ
ĭ
İ
ı
Į
į
Ĵ
ĵ
Ķ
ķ
Ĺ
ĺ
Ļ
ļ
Ľ
ľ
Ł
ł
Ń
ń
Ñ
ñ
Ņ
ņ
Ň
ň
Ó
ó
Ò
ò
Ô
ô
Ö
ö
Õ
õ
Ǒ
ǒ
Ō
ō
Ŏ
ŏ
Ǫ
ǫ
Ő
ő
Ŕ
ŕ
Ŗ
ŗ
Ř
ř
Ś
ś
Ŝ
ŝ
Ş
ş
Š
š
Ș
ș
Ț
ț
Ť
ť
Ú
ú
Ù
ù
Û
û
Ü
ü
Ũ
ũ
Ů
ů
Ǔ
ǔ
Ū
ū
ǖ
ǘ
ǚ
ǜ
Ŭ
ŭ
Ų
ų
Ű
ű
Ŵ
ŵ
Ý
ý
Ŷ
ŷ
Ÿ
ÿ
Ȳ
ȳ
Ź
ź
Ž
ž
Ż
ż
Æ
æ
Ǣ
ǣ
Ø
ø
Œ
œ
ß
Ð
ð
Þ
þ
Ə
ə
서식 지정
링크
문단 제목
목록
파일
토론
설명
입력하는 내용
문서에 나오는 결과
기울임꼴
''기울인 글씨''
기울인 글씨
굵게
'''굵은 글씨'''
굵은 글씨
굵은 글씨와 기울인 글씨
'''''굵고 기울인 글씨'''''
굵고 기울인 글씨
/** * pluginX Core * pluginX 시스템이 제대로 돌아가게 해 줍니다. * 작성자: [[사용자:Bd3076|Bd3076]] * v2.0.0 전체수정 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 7월 9일 (일) 23:20 (KST) * v2.0.1 스크립트 해쉬값 검증 추가 --[[사용자:BANIP|BANIP]] 2023년 7월 10일 (월) 09:53 (KST) * v2.0.2 자바스크립트가 위키텍스트로 파싱되는 문제 수정에 대한 스크립트쪽 소스 대응 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 9월 4일 (월) 10:40 (KST) */ function pluginXCore() { //pluginX를 문서에서 사용하지 않으면 종료 if ($("#bodyContent .pluginx-script-wrapper").length == 0) return; // 플러그인 목록 반환 var getPluginList = function() { var pluginItems = []; /// 현재 문서 페이지에서 필요한 플러그인 수집 $("#bodyContent .pluginx-script-wrapper").each(function() { var $this = $(this); var url = $this.data('url'); // 이미 추가된 플러그인이면 추가하지 않음 if (pluginItems.find(function(item) { return item.url == url; })) return; var script = $this.text(); // 플러그인 목록에 추가 pluginItems.push({ url: url, name: $this.data('name'), creator: $this.data('creator'), doc: $this.data('doc'), revid: $this.data('rev-id'), script: script, revTimestamp: $this.data('rev-timestamp'), revUser: $this.data('rev-user'), scriptHash:cyrb53(script), }); }); return pluginItems; }; var cyrb53 = function(str, seed){ if(seed === undefined) seed = 0; var h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; for(var i = 0, ch; i < str.length; i++) { ch = str.charCodeAt(i); h1 = Math.imul(h1 ^ ch, 2654435761); h2 = Math.imul(h2 ^ ch, 1597334677); } h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); return 4294967296 * (2097151 & h2) + (h1 >>> 0); }; var setting = { STORAGE_IDENTIFIER: "gadget-pluginx", DEFAULT_CONFIG_TEXT:'{"trusted": [], "resetflag": ' + new Date().getTime() + ' }', get: function(){ // trusted: {doc:string, revid, revUser:string, revTimestamp:string, }[] return JSON.parse(localStorage.getItem(setting.STORAGE_IDENTIFIER) || setting.DEFAULT_CONFIG_TEXT); }, getTrustedItems: function(){ return setting.get().trusted; }, getTrustedItemByDoc: function(doc){ return setting.getTrustedItems().find(function(item){ return item.doc == doc; }); }, set: function(data){ localStorage.setItem(setting.STORAGE_IDENTIFIER, JSON.stringify(data)); }, setTrustedItems: function(items){ var data = setting.get(); items.forEach(function(item){ var itemForPush = { revid : item.revid, revTimestamp : item.revTimestamp, revUser : item.revUser, doc : item.doc, scriptHash : item.scriptHash, }; var index = data.trusted.findIndex(function(trustedItem){ return trustedItem.doc == item.doc; }); if(index == -1){ data.trusted.push(itemForPush); }else{ data.trusted[index] = itemForPush; } }); setting.set(data); }, reset: function(){ localStorage.setItem(setting.STORAGE_IDENTIFIER,setting.DEFAULT_CONFIG_TEXT); }, }; var installPopup = { // 플러그인 인스톨 페이지 가져오기 _getPopupElement:function(option){ option = option || {}; resolveCallback = option.resolveCallback || function(){}; rejectCallback = option.rejectCallback || function(){}; if(installPopup._$popupWrapper === undefined){ // 설치 팝업 생성 var $popupWrapperOrigin = $('' + '<div class="pluginx-popup-wrapper">' + '<div class="pluginx-popup">' + '<div class="pluginx-popup-header">' + '<div class="pluginx-popup-title">플러그인 설치가 필요합니다.</div>' + '</div>' + '<div class="pluginx-popup-content-wrapper">' + '<div class="pluginx-popup-content">' + '<div class="pluginx-popup-code"></div>' + '<div class="pluginx-popup-summary"></div>' + '</div>' + '</div>' + '<div class="pluginx-popup-footer">' + '<div class="pluginx-trust-check-wrapper">' + '<input type="checkbox" id="pluginx-trust-check" checked="checked" />' + '<label for="pluginx-trust-check" >다시 묻지 않기</label>' + '</div>' + '<div class="pluginx-btn-accept pluginx-close pluginx-btn">사용</div>' + '<div class="pluginx-btn-deny pluginx-close pluginx-btn">거부</div>' + '</div>' + '</div>' + '</div>'); // 만든팝업 캐싱 installPopup._$popupWrapper = $popupWrapperOrigin; } var $popupWrapper = installPopup._$popupWrapper.clone(); var closePopup = function(callback){ $popupWrapper.closest(".pluginx-popup-wrapper").fadeOut(0.3, function(){ $popupWrapper.remove(); callback($popupWrapper); }); }; // 팝업 외부 클릭시 팝업 종료 $popupWrapper.click(function(e){ if(e.target == $popupWrapper[0]){ closePopup(rejectCallback); } }) // 팝업 종료 이벤트 $popupWrapper.find(".pluginx-btn-accept").click(function(){ closePopup(resolveCallback); }); $popupWrapper.find(".pluginx-btn-deny").click(function(){ closePopup(rejectCallback); }); return $popupWrapper; }, // 플러그인 인스톨 페이지에 설정값 바인딩 후 표시 show:function(pluginItems){ return new Promise(function(resolve, reject){ var $popupWrapper = installPopup._getPopupElement({ resolveCallback: function($popupWrapper){ resolve({ trust: $popupWrapper.find("#pluginx-trust-check").is(":checked"), }); }, rejectCallback: function(){ reject(); }, }); var formatTimestamp = function(timestamp){ timestamp = timestamp.toString(); return timestamp.substring(0,4) + "-" + timestamp.substring(4,6) + "-" + timestamp.substring(6,8) + " " + timestamp.substring(8,10) + ":" + timestamp.substring(10,12) + ":" + timestamp.substring(12,14); }; pluginItems.forEach(function(pluginItem){ var $plugin = $popupWrapper.find(".pluginx-popup-content").eq(0).clone().css({display: "block"}); $plugin.find(".pluginx-popup-code").text(pluginItem.script); // 자동 이스케이프 $plugin.find(".pluginx-popup-summary").append("<li> 플러그인 이름 : " + pluginItem.name + "</li>"); $plugin.find(".pluginx-popup-summary").append("<li> 원본문서 : " + pluginItem.doc + "</li>"); $plugin.find(".pluginx-popup-summary").append("<li> 원본 문서 편집자 : " + pluginItem.creator + "</li>"); $plugin.find(".pluginx-popup-summary").append("<li> 스크립트 수정자 : " + pluginItem.revUser + "</li>"); $plugin.find(".pluginx-popup-summary").append("<li> 수정일 : " + formatTimestamp(pluginItem.revTimestamp) + "</li>"); var patternList = [ { // 이전 신뢰된 편집자와 현재 편집자가 다른 경우 ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid && pluginItem.prevTrusted.revUser !== pluginItem.revUser; }, severity: "alert", message: "이전 신뢰된 편집자와 현재 편집자가 다릅니다. 사용자를 확인하시고 토론 문서 등에 스크립트 수정에 관한 언급이 없는 사용자가 편집한 경우 실행하지 않는 것을 권장합니다. 그래도 실행을 허용하려면 5초 간 기다려주세요.", }, { // 신뢰된 버전과 현재 버전의 리비전이 동일한 경우 ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid === pluginItem.revid && pluginItem.prevTrusted.revUser === pluginItem.revUser && pluginItem.prevTrusted.scriptHash === pluginItem.scriptHash; }, severity: "safe", message: "이전에 신뢰된 플러그인입니다.", }, {// 이전에 신뢰되었지만 현재 버전이 다른 경우 ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid && pluginItem.prevTrusted.revid !== pluginItem.revid && pluginItem.prevTrusted.revUser === pluginItem.revUser; }, severity: "safe", message: "이전에 신뢰되었지만 버전업으로 재확인이 필요합니다.", }, { // 이전에 신뢰된 버전이랑 리비전은 같은데 스크립트 해쉬가 다른 경우 ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid === pluginItem.revid && pluginItem.prevTrusted.scriptHash !== pluginItem.scriptHash && pluginItem.prevTrusted.scriptHash; }, severity: "danger", message: "이전에 신뢰된 버전과 스크립트가 다른걸로 확인됩니다. 스크립트가 조작되었거나 PluginX 자체가 고장났을 가능성이 크므로, 설치하지 말고 관리자에게 알려주세요.", }, { // 이전버전 해쉬가 없을때(스크립트 해쉬를 사용하지 않는 구버전 스크립트를 사용했을 때) ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid === pluginItem.revid && pluginItem.prevTrusted.scriptHash !== pluginItem.scriptHash && !pluginItem.prevTrusted.scriptHash; }, severity: "safe", message: "이전에 신뢰된 스크립트이나 플러그인X 버전업으로 재확인이 필요합니다.", }, ]; for(var patternKey in patternList){ var pattern = patternList[patternKey]; if(pattern.ciritica(pluginItem)){ $plugin.find(".pluginx-popup-summary").append("<li class='severity " + pattern.severity + "'>" + pattern.message + "</li>"); // danger일 때 저장링크 비활성화 if(pattern.severity === "danger"){ $popupWrapper.find(".pluginx-btn-accept").remove(); } else if (pattern.severity === "alert") { // alert의 경우 저장 링크를 숨기고, 3초 기다려야 허용 버튼이 뜬다. $popupWrapper.find(".pluginx-btn-accept").hide(); $popupWrapper.find(".pluginx-btn-accept").show(5000); } } } $popupWrapper.find(".pluginx-popup-content-wrapper").append($plugin); }); $popupWrapper.appendTo("body").fadeIn(0.2); })}, }; var executePluginItems = function(pluginItems){ pluginItems.forEach(function(pluginItem){ eval(pluginItem.script); }); var pluginNames = pluginItems.map(function(pluginItem){ return pluginItem.name; }).join(", "); $("#siteSub").text(function(i,prev){ return prev + " - PluginX " + pluginNames + " 사용중"}); }; /* -------------- 플러그인 체크 로직 시작 ---------------- */ // 신뢰여부 리셋 관련 (function(){ // 사용자 플러그인의 전체 신뢰 여부를 리셋할 필요가 있을 경우 (new Date().getTime()) 값으로 아래 상수를 수정 해 주세요 var LAST_RESET_TIME = 1693787747000; var settingInstance = setting.get(); if( (settingInstance.resetflag || 0) < LAST_RESET_TIME ){ setting.reset(); } })(); // 문서에서 사용중인 플러그인 확인 var pluginItems = getPluginList(); // 모든 플러그인의 신뢰여부 체크 pluginItems = pluginItems.map(function(pluginItem){ return Object.assign(pluginItem, {prevTrusted: setting.getTrustedItemByDoc(pluginItem.doc) || {}}); }); // 플러그인의 신뢰여부 확인 var isPluginTrusted = pluginItems.every(function(pluginItem){ return pluginItem.prevTrusted.revid === pluginItem.revid && pluginItem.prevTrusted.scriptHash === pluginItem.scriptHash; }); // 기존 pluginx-need-alert 삭제 $("#bodyContent .mw-parser-output .pluginx-need-alert").remove(); if( isPluginTrusted ){ // 스크립트 실행 executePluginItems(pluginItems); } else { var requestAlert = $('<div class="pluginx-need-alert mw-message-box-success mw-message-box"><p><strong><a>이 문서를 정상적으로 보려면 스크립트 허용이 필요해요.</a></strong></p></div>') $("#bodyContent .mw-parser-output").prepend(requestAlert); requestAlert.find("a").click(function(){ // todo localstoarge에서 대조 후 리비전이 다를때만 사용자 확인 필요 installPopup.show(pluginItems).then(function(result){ result = result || {}; // 사용자가 플러그인을 신뢰할 경우 localStoarge에 저장 if(result.trust){ setting.setTrustedItems(pluginItems); } // 스크립트 실행 executePluginItems(pluginItems); requestAlert.remove(); }); }); } } $(pluginXCore);
미디어위키:Gadget-PluginX.js
문서로 돌아갑니다.