Saving Checkpoint before I'm doing *risky* things

This commit is contained in:
Jean Ouina 2020-07-28 03:02:29 +02:00
parent e47e1b0158
commit df6c9c4203
31 changed files with 1065 additions and 163 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://paypal.me/jenwina'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

4
.gitignore vendored
View File

@ -110,3 +110,7 @@ builds
dist dist
distApp distApp
# discord_voice debug
discord-last-webrtc_0
discord-webrtc_0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4186,7 +4186,7 @@
}, },
"kind-of": { "kind-of": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
"dev": true "dev": true
}, },
@ -6505,7 +6505,7 @@
}, },
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -6614,7 +6614,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true, "dev": true,
"requires": { "requires": {

View File

@ -76,6 +76,7 @@ export const settings = {
"Scroll To Settings": {id: "fork-ps-3", info: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)", implemented: true, hidden: false, cat: "core", category: "content manager"}, "Scroll To Settings": {id: "fork-ps-3", info: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)", implemented: true, hidden: false, cat: "core", category: "content manager"},
"Automatic Loading": {id: "fork-ps-5", info: "Automatically loads, reloads, and unloads plugins and themes", implemented: true, hidden: false, cat: "core", category: "content manager"}, "Automatic Loading": {id: "fork-ps-5", info: "Automatically loads, reloads, and unloads plugins and themes", implemented: true, hidden: false, cat: "core", category: "content manager"},
"Enable Edit Button": {id: "fork-ps-7", info: "Enable an Edit Button on the plugin and theme panel.", implemented: true, hidden: false, cat: "core", category: "content manager"}, "Enable Edit Button": {id: "fork-ps-7", info: "Enable an Edit Button on the plugin and theme panel.", implemented: true, hidden: false, cat: "core", category: "content manager"},
"Themes in Popout Window": {id: "lightcord-9", info: "Enable themes in Popout Window. (For example, when detaching screenshare.)", implemented: true, hidden: false, cat: "core", category: "content manager", experimental: true},
/* Developer */ /* Developer */
"Developer Mode": {id: "bda-gs-8", info: "Developer Mode Toggle", implemented: true, hidden: false, cat: "core", category: "developer settings"}, "Developer Mode": {id: "bda-gs-8", info: "Developer Mode Toggle", implemented: true, hidden: false, cat: "core", category: "developer settings"},
@ -146,6 +147,7 @@ export const defaultCookie = {
"lightcord-6": true, "lightcord-6": true,
"lightcord-7": false, "lightcord-7": false,
"lightcord-8": false, "lightcord-8": false,
"lightcord-9": false,
"lightcord-10": false, "lightcord-10": false,
"no_window_bound": false, "no_window_bound": false,
}; };

View File

@ -143,6 +143,7 @@ Core.prototype.init = async function() {
Utils.suppressErrors(this.patchMessageHeader.bind(this), "BD Badge Chat Patch")(); Utils.suppressErrors(this.patchMessageHeader.bind(this), "BD Badge Chat Patch")();
Utils.suppressErrors(this.patchMemberList.bind(this), "BD Badge Member List Patch")(); Utils.suppressErrors(this.patchMemberList.bind(this), "BD Badge Member List Patch")();
Utils.suppressErrors(this.patchAttachment.bind(this), "LC Plugin Certifier Patch")(); Utils.suppressErrors(this.patchAttachment.bind(this), "LC Plugin Certifier Patch")();
Utils.suppressErrors(this.patchPopoutWindow.bind(this), "BD Popout Window Patch")();
if(bdConfig.haveInstalledDefault){ if(bdConfig.haveInstalledDefault){
let alert = Utils.alert("First Installation", "As it is the first time you install Lightcord, We added two default themes and one default plugin in your plugin/theme folder. Check it in the Plugin/Theme settings.") let alert = Utils.alert("First Installation", "As it is the first time you install Lightcord, We added two default themes and one default plugin in your plugin/theme folder. Check it in the Plugin/Theme settings.")
@ -161,6 +162,48 @@ Core.prototype.init = async function() {
} }
}; };
Core.prototype.patchPopoutWindow = async function() {
let canceled = false
this.cancelPatchPopoutWindow = () => {
canceled = true
}
window.Lightcord.Api.ensureExported(e => e.default && e.default.getWindow)
.then(popoutModule => {
if(canceled)return
// Not a good idea to do it like that.
const interceptor = window.Lightcord.DiscordModules.dispatcher._interceptor
window.Lightcord.DiscordModules.dispatcher.setInterceptor(function(action){
if(action && action.type === "POPOUT_WINDOW_OPEN"){
const render = action.render
action.render = function(){
const render1 = render.call(this, ...arguments)
const type1 = render1.type
render1.type = function(props){
const render2 = type1(props)
console.log(props, render2)
return render2
}
console.log(render1)
return render1
}
}
return interceptor.call(this, action)
})
window.Lightcord.DiscordModules.dispatcher.subscribe("POPOUT_WINDOW_OPEN", (ev) => {
if(!settingsCookie["lightcord-9"])return
if(canceled)return
Utils.log("POPOUT THEME", "Popout opened, Adding theme")
setImmediate(() => {
console.log(ev)
const window = popoutModule.default.getWindow(ev.key)
console.log(window)
})
})
})
};
Core.prototype.patchAttributes = async function() { Core.prototype.patchAttributes = async function() {
let attribsPatchs = [] let attribsPatchs = []
this.cancelPatchAttributes = function() { this.cancelPatchAttributes = function() {
@ -171,7 +214,7 @@ Core.prototype.patchAttributes = async function() {
// TODO: try to patch correctly the user popout on a next update // TODO: try to patch correctly the user popout on a next update
const Anchor = WebpackModules.find(m => m.displayName == "Anchor"); const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
ensureExported(e => e.default && e.default.displayName === "DiscordTag") window.Lightcord.Api.ensureExported(e => e.default && e.default.displayName === "DiscordTag")
.then(DiscordTag => { .then(DiscordTag => {
let DiscordTagComp = DiscordTag.default let DiscordTagComp = DiscordTag.default
DiscordTag.default = function(props){ DiscordTag.default = function(props){
@ -282,6 +325,7 @@ Core.prototype.initSettings = function () {
settingModule.default.prototype.getPredicateSections = function(){ settingModule.default.prototype.getPredicateSections = function(){
let result = getPredicateSections.call(this, ...arguments) let result = getPredicateSections.call(this, ...arguments)
if(!result[1])return result
if(result[1].section === "My Account"){ // user settings, not guild settings if(result[1].section === "My Account"){ // user settings, not guild settings
let poped = [] let poped = []

View File

@ -30,10 +30,13 @@ export default class ApiPreview extends React.PureComponent {
<formModule.FormSection tag="h2" title="Lightcord's Api Availlable components"> <formModule.FormSection tag="h2" title="Lightcord's Api Availlable components">
<formModule.FormText type="description" className="" selectable={false}> <formModule.FormText type="description" className="" selectable={false}>
These components are here for the plugin devs. They can quickly embed any component below with this panel. These components are here for the plugin devs. They can quickly embed any component below with this panel.
<div style={{marginTop: "20px"}}></div>
<Lightcord.Api.Components.general.AlertBox type="info">All these components have error handling. If you want none, add `.original` after the component path.</Lightcord.Api.Components.general.AlertBox>
<Lightcord.Api.Components.general.AlertBox type="warn">We do not recommend modifying these component by a plugin. Only do this if you know what you are doing.</Lightcord.Api.Components.general.AlertBox>
</formModule.FormText> </formModule.FormText>
<MarginTop></MarginTop> <MarginTop></MarginTop>
<Lightcord.Api.Components.inputs.Button color="brand" look="outlined" size="medium" hoverColor="green" onClick={() => { <Lightcord.Api.Components.inputs.Button color="brand" look="outlined" size="medium" hoverColor="green" onClick={() => {
remote.shell.openExternal("https://github.com/lightcord/lightcord/wiki/Apis") remote.shell.openExternal("https://lightcord.deroku.xyz/LightcordApi/docs")
}} wrapper={false}> }} wrapper={false}>
Documentation Documentation
</Lightcord.Api.Components.inputs.Button> </Lightcord.Api.Components.inputs.Button>

View File

@ -572,7 +572,7 @@ class PresenceErrorCatcher extends React.Component {
return this.render() return this.render()
} }
}else{ }else{
emptyClasses = emptyClasses || BDV2.WebpackModules.find(e => e.emptyStateImage) emptyClasses = emptyClasses || BDV2.WebpackModules.find(e => e.emptyStateImage && e.emptyState)
if(!emptyClasses){ if(!emptyClasses){
Utils.showToast("An error occured. Please check the console for more informations.") Utils.showToast("An error occured. Please check the console for more informations.")
return null return null
@ -584,7 +584,7 @@ class PresenceErrorCatcher extends React.Component {
backgroundColor: "var(--background-primary)", backgroundColor: "var(--background-primary)",
padding: "30px 30px", padding: "30px 30px",
borderRadius: "8px" borderRadius: "8px"
}} className="lc-tab-box-shadow"> }} className={`lc-tab-box-shadow ${emptyClasses.emptyState}`}>
<div className={emptyClasses.emptyStateImage} style={{ <div className={emptyClasses.emptyStateImage} style={{
marginTop: "20px" marginTop: "20px"
}}> }}>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@
"build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none", "build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none",
"watch-prod": "webpack --progress --colors --watch --mode production -o js/main.min.js --devtool none", "watch-prod": "webpack --progress --colors --watch --mode production -o js/main.min.js --devtool none",
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"docs": "typedoc --plugin ./node_modules/typedoc-plugin-markdown --out ../../LightcordApiDocs ./src" "docs": "typedoc --out ../../LightcordApiDocs ./src"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",

View File

@ -1,2 +1,28 @@
// bait typescript into thinking this is not reactDOM so no circular dependency. import { ReactDOMSelector } from "./selectors"
export = window["Reac"+"tDOM"] as typeof import("react-dom")
// bait typescript into thinking this is not reactDOM so no circular dependency.
window.ReactDOM = (window["Reac"+"tDOM"] || // If in Lightcord
(()=>{ // If in Standard BetterDiscord
try{
return window.BdApi.findModule(ReactDOMSelector as any)
}catch(e){
return null
}
})() ||
(()=>{ // If in Powercord
try{
const webpack = require("powercord/webpack")
return webpack.ReactDOM
}catch(e){
return null
}
})() ||
(()=>{ // If in EnhancedDiscord
try{
return window.EDApi.findModule(ReactDOMSelector as any)
}catch(e){
return null
}
})()) as typeof import("react-dom")
export = (window.ReactDOM as any)

View File

@ -1 +1,27 @@
import { ReactSelector } from "./selectors";
window.React = (window.React || // If in Lightcord
(()=>{ // If in Standard BetterDiscord
try{
return window.BdApi.findModule(ReactSelector as any)
}catch(e){
return null
}
})() ||
(()=>{ // If in Powercord
try{
const webpack = require("powercord/webpack")
return webpack.React
}catch(e){
return null
}
})() ||
(()=>{ // If in EnhancedDiscord
try{
return window.EDApi.findModule(ReactSelector as any)
}catch(e){
return null
}
})()) as typeof import("react")
export = window.React export = window.React

View File

@ -0,0 +1,2 @@
export const ReactSelector = mod => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].find(k => !mod[k])
export const ReactDOMSelector = mod => mod.findDOMNode

View File

@ -13,25 +13,27 @@ import cloneNullProto from "../modules/cloneNullProto"
import Tooltip from "./general/Tooltip" import Tooltip from "./general/Tooltip"
import ColorPicker from "./inputs/ColorPicker" import ColorPicker from "./inputs/ColorPicker"
import AlertBox from "./general/AlertBox" import AlertBox from "./general/AlertBox"
import { createProxyErrorCatcherClass } from "./private/ErrorCatcher"
const RadioGroupProxied = createProxyErrorCatcherClass(RadioGroup)
export default cloneNullProto({ export default cloneNullProto({
inputs: cloneNullProto({ inputs: cloneNullProto({
Button: DiscordButton, Button: createProxyErrorCatcherClass(DiscordButton),
Switch: Switch, Switch: createProxyErrorCatcherClass(Switch),
Choices: RadioGroup, Choices: RadioGroupProxied,
RadioGroup: RadioGroup, RadioGroup: RadioGroupProxied,
TextArea: TextArea, TextArea: createProxyErrorCatcherClass(TextArea),
TextInput: TextInput, TextInput: createProxyErrorCatcherClass(TextInput),
Dropdown: Dropdown, Dropdown: createProxyErrorCatcherClass(Dropdown),
ColorPicker: ColorPicker ColorPicker: createProxyErrorCatcherClass(ColorPicker)
}), }),
general: cloneNullProto({ general: cloneNullProto({
Title: Title, Title: createProxyErrorCatcherClass(Title),
SettingsTitle: SettingsTitle, SettingsTitle: createProxyErrorCatcherClass(SettingsTitle),
SettingSubTitle: SettingSubTitle, SettingSubTitle: createProxyErrorCatcherClass(SettingSubTitle),
Tabs: Tabs, Tabs: createProxyErrorCatcherClass(Tabs),
CodeBlock: CodeBlock, CodeBlock: createProxyErrorCatcherClass(CodeBlock),
Tooltip: Tooltip, Tooltip: createProxyErrorCatcherClass(Tooltip),
AlertBox: AlertBox AlertBox: createProxyErrorCatcherClass(AlertBox)
}) })
}) })

View File

@ -2,6 +2,7 @@ import NOOP from "../../modules/noop"
import WebpackLoader from "../../modules/WebpackLoader" import WebpackLoader from "../../modules/WebpackLoader"
import Tooltip from "../general/Tooltip" import Tooltip from "../general/Tooltip"
import Utils from "../../modules/Utils" import Utils from "../../modules/Utils"
import { createProxyErrorCatcherClass } from "../private/ErrorCatcher"
const Constants = { const Constants = {
defaultColor: 10070709, defaultColor: 10070709,
@ -57,9 +58,13 @@ export default class ColorPicker extends React.PureComponent<ColorPickerProps, {
/** Preload the component. */ /** Preload the component. */
static preload(){ static preload(){
if(ColorPicker.prototype.modules[0])return if(ColorPicker.prototype.modules[0])return // already loaded
if(isFetching)return if(isFetching)return // is fetching so don't double preload.
new ColorPicker({}).render() try{ // If we caught an error
new ColorPicker({}).render()
}catch(e){
console.error(e)
}
} }
onChange(val){ onChange(val){
@ -114,9 +119,10 @@ export default class ColorPicker extends React.PureComponent<ColorPickerProps, {
return { return {
id: null id: null
} }
} },
renderHeader: GuildSettingsRoles.prototype.renderHeader
}) })
const GuildRoleSettings = settings.props.children.type const GuildRoleSettings = settings.props.children[1].type
let children = GuildRoleSettings.prototype.renderColorPicker.call({ let children = GuildRoleSettings.prototype.renderColorPicker.call({
props: { props: {
role: { role: {
@ -128,6 +134,7 @@ export default class ColorPicker extends React.PureComponent<ColorPickerProps, {
} }
}).props.children }).props.children
children.type(children.props).props.children.type._ctor().then(c => { children.type(children.props).props.children.type._ctor().then(c => {
ColorPickerModules = null
this.forceUpdate() this.forceUpdate()
resolve() resolve()
}) })
@ -175,7 +182,7 @@ export default class ColorPicker extends React.PureComponent<ColorPickerProps, {
} }
static help = { static help = {
info: "To convert hex colors to decimal, you can do `Lightcord.Api.Utils.HexColorToDecimal('#yourcolor')` and go back with `Lightcord.Api.Utils.DecimalColorToHex(7506394)`", info: "To convert hex colors to decimal, you can do `Lightcord.Api.Utils.HexColorToDecimal('#7289DA')` and go back with `Lightcord.Api.Utils.DecimalColorToHex(7506394)`",
warn: "The component may not appear instantly. The component needs to be loaded, so you could experience 50-300ms loading time depending on your internet connection." warn: "The component may not appear instantly. The component needs to be loaded, so you could experience 50-300ms loading time depending on your internet connection."
} }
} }

View File

@ -0,0 +1,97 @@
import { ReactNode } from "react";
import WebpackLoader from "../../modules/WebpackLoader";
import DiscordTools from "../../modules/DiscordTools";
import NOOP from "../../modules/noop";
import uuid from "../../modules/uuid";
type ErrorCatcherProps = {
children: ReactNode
}
let ErrorCatcherModules
export default class ErrorCatcher extends React.Component<ErrorCatcherProps, {error: boolean, hasSentNotification: boolean}> {
constructor(props:ErrorCatcherProps){
super(props)
this.state = {
error: false,
hasSentNotification: false
}
}
get modules():any[]{
return ErrorCatcherModules || (ErrorCatcherModules = [
WebpackLoader.find(e => e.emptyStateImage && e.emptyState)
])
}
defaultProps:ErrorCatcherProps = {
children: null
}
render(){
if(!this.state.error){
return this.props.children
}else{ // try to render a user-friendly interface.
const [
emptyClasses
] = this.modules
if(!emptyClasses){ // If we can't, render nothing and show a notification.
if(this.state.hasSentNotification)return null // If the notification was already sent, don't send one.
const notification = DiscordTools.showNotification({
body: "An error occured. Please check the console for more informations.",
icon: "https://github.com/lightcord.png",
onClick: NOOP,
onClose: NOOP,
onShow: NOOP,
title: "Lightcord Informations"
})
this.setState({
hasSentNotification: true
})
setTimeout(() => {
notification.close()
}, 2000)
return null
}
return <div className={emptyClasses.emptyState}>
<div className={emptyClasses.emptyStateImage} style={{
marginTop: "20px"
}}></div>
<div className={emptyClasses.emptyStateHeader}>An error occured</div>
<p className={emptyClasses.emptyStateSubtext}>
Please check the console for more informations. Join our ­support server for more help.
</p>
</div>
}
}
componentDidCatch(error, errorInfo){
console.error(errorInfo.componentStack)
this.setState({
error: true
})
}
}
export function createProxyErrorCatcherClass<base = Function>(Class:base):base & {
readonly original: base
}{
const ClassCopy = (class Proxied extends React.Component {
render(){
return <ErrorCatcher key={uuid()}>
{React.createElement(Class as any, {...this.props, key: uuid()})}
</ErrorCatcher>
}
static displayName = Class["displayName"] || Class["name"]
static get original(){
return Class
}
}) as any
Object.entries(Object.getOwnPropertyDescriptors(Class)).forEach(value => {
if(value[0] in ClassCopy)return
Object.defineProperty(ClassCopy, value[0], value[1])
})
return ClassCopy
}

View File

@ -8,6 +8,8 @@ import excludeProperties from "./modules/excludeProperties"
import cloneNullProto from "./modules/cloneNullProto" import cloneNullProto from "./modules/cloneNullProto"
import NOOP from "./modules/noop" import NOOP from "./modules/noop"
import unfreeze from "./modules/Unfreeze" import unfreeze from "./modules/Unfreeze"
import { isNative, isImported } from "./modules/environnement"
import * as bandagedbdApi from "@bandagedbd/bdapi"
patchers.patch() patchers.patch()
const LightcordApi = { const LightcordApi = {
@ -21,19 +23,29 @@ const LightcordApi = {
cloneNullProto: cloneNullProto, cloneNullProto: cloneNullProto,
NOOP: NOOP, NOOP: NOOP,
unfreeze: unfreeze unfreeze: unfreeze
} },
get isNative(){return isNative},
get isImported(){return isImported}
} }
declare global { declare global {
var React:typeof import("react") var React:typeof import("react")
interface Window { interface Window {
/**
* Lightcord is only availlaible in Lightcord (native)
*/
Lightcord: LightcordGlobal, Lightcord: LightcordGlobal,
/**
* BDModules is only availlaible in Lightcord (native)
*/
BDModules: { BDModules: {
modules:any[], modules:any[],
get(filter:(mod:any)=>boolean, modules?:any[]):any[], get(filter:(mod:any)=>boolean, modules?:any[]):any[],
get(id:number, modules?:any[]):any, get(id:number, modules?:any[]):any,
get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any
} },
BdApi: typeof bandagedbdApi.BdApi,
EDApi: typeof bandagedbdApi.BdApi
} }
var Lightcord:LightcordGlobal var Lightcord:LightcordGlobal
} }
@ -59,7 +71,7 @@ export interface LightcordGlobal {
}, },
Api: LightcordApiGlobal, Api: LightcordApiGlobal,
BetterDiscord: { BetterDiscord: {
BdApi: typeof import("@bandagedbd/bdapi").BdApi, BdApi: typeof bandagedbdApi.BdApi,
[mod:string]:any [mod:string]:any
} }
} }

View File

@ -0,0 +1,82 @@
let req
setReq()
function filterDangerous(mods){
return mods.map(e => {
return protect(e)
})
}
function protect(exports){
let theModule = exports.exports
let mod = theModule.default
if(!mod)return exports
if (mod.remove && mod.set && mod.clear && mod.get && !mod.sort) return null;
if (!mod.getToken && !mod.getEmail && !mod.showToken)return exports
const proxy = new Proxy(mod, {
getOwnPropertyDescriptor: function(obj, prop) {
if (prop === "getToken" || prop === "getEmail" || prop === "showToken") return undefined;
return Object.getOwnPropertyDescriptor(obj, prop);
},
get: function(obj, func) {
if (func == "getToken" && obj.getToken) return () => "mfa.XCnbKzo0CLIqdJzBnL0D8PfDruqkJNHjwHXtr39UU3F8hHx43jojISyi5jdjO52e9_e9MjmafZFFpc-seOMa";
if (func == "getEmail" && obj.getEmail) return () => "puppet11112@gmail.com";
if (func == "showToken" && obj.showToken) return () => true;
if (func == "__proto__" && obj.__proto__) return proxy;
return obj[func];
}
});
return Object.assign({}, exports, {exports: Object.assign({}, theModule, {default: proxy})})
}
class Webpackloader {
get modules(){
if(req){
return filterDangerous(Object.values(req.c).filter((e:any) => e && e.exports))
}else{
setReq()
if(req){
return filterDangerous(Object.values(req.c).filter((e:any) => e && e.exports))
}else{
return []
}
}
}
get(ids, modules){
if(typeof ids === "function"){
return (modules || this.modules).map((mdl) => {
if(mdl && typeof mdl.exports !== "undefined"){
return mdl.exports
}else{
return null
}
}).filter(e => e).filter(ids)
}else if(Array.isArray(ids)){
modules = modules || this.modules
return ids.map(id => this.get(id, modules))
}else{
modules = modules || this.modules
let module = modules.filter(e => !!e).find(e => e.i === ids)
if(!module)return undefined
return module.exports
}
}
get default(){
return this
}
}
export default new Webpackloader()
function setReq(){
try{
req = window["webpackJsonp"].push([[], {__extra_id__: (mdl, exports, req) => mdl.exports = req}, [["__extra_id__"]]]);
if(req){
delete req.m.__extra_id__;
delete req.c.__extra_id__;
}
}catch(e){
req = undefined
}
}

View File

@ -152,6 +152,8 @@ export class Notice extends EventEmitter {
index:number index:number
} }
private nextTickRefresh:boolean = false
get removed():boolean{ get removed():boolean{
return !notices.find(e => e.id === this.id) return !notices.find(e => e.id === this.id)
} }
@ -166,36 +168,55 @@ export class Notice extends EventEmitter {
return this.data.id return this.data.id
} }
update(data: Partial<notice>){
for(let key in data){
if(key === "id")continue
this.data[key] = data[key]
}
if(!this.nextTickRefresh){
this.nextTickRefresh = true
process.nextTick(() => {
this.nextTickRefresh = false
noticeEvents.emit("noticeUpdate")
})
}
}
get text(){ get text(){
return this.data.text return this.data.text
} }
set text(text){ set text(text){
this.data.text = text this.update({
noticeEvents.emit("noticeUpdate") text
})
} }
get type(){ get type(){
return this.data.type return this.data.type
} }
set type(type){ set type(type){
this.data.type = type this.update({
noticeEvents.emit("noticeUpdate") type
})
} }
get buttonText(){ get buttonText(){
return this.data.buttonText return this.data.buttonText
} }
set buttonText(buttonText:string){ set buttonText(buttonText:string){
this.data.buttonText = buttonText this.update({
noticeEvents.emit("noticeUpdate") buttonText
})
} }
get onClick(){ get onClick(){
return this.data.onClick return this.data.onClick
} }
set onClick(onClick){ set onClick(onClick){
this.data.onClick = onClick this.update({
noticeEvents.emit("noticeUpdate") onClick
})
} }
remove(){ remove(){

View File

@ -1,4 +1,4 @@
const BDModules = window.BDModules const BDModules:typeof window.BDModules = window.BDModules || require("./BDModules")
export default new class WebpackLoader { export default new class WebpackLoader {
constructor(){} constructor(){}
@ -50,7 +50,7 @@ export default new class WebpackLoader {
export class WebpackLoaderError extends Error { export class WebpackLoaderError extends Error {
constructor(message:string = ""){ constructor(message:string = ""){
message += "\n\tThis error is related to Lightcord not being able to find a WebpackModule. \n\tPlease show this error and a few lines of logs above this error. \n\tOpen an issue on https://github.com/Lightcord/Lightcord or in their discord server." message += "\n\tThis error is related to Lightcord not being able to find a WebpackModule. \n\tPlease show this error and a few lines of logs above this error to the devs. \n\tOpen an issue on https://github.com/Lightcord/Lightcord or in our discord server."
super(message) super(message)
this.name = "WebpackLoaderError" this.name = "WebpackLoaderError"
} }

View File

@ -0,0 +1,2 @@
export const isNative:boolean = typeof window.BDModules === "undefined"
export const isImported:boolean = typeof window.BDModules !== "undefined"

View File

View File

@ -1,5 +1,6 @@
import Utils from "./Utils" import Utils from "./Utils"
import Notices, { notices } from "../components/private/Notices" import Notices, { notices } from "../components/private/Notices"
import { isNative } from "./environnement";
export function patch(){ export function patch(){
/** START NOTICE */ /** START NOTICE */
@ -47,6 +48,62 @@ export function patch(){
}) })
/** END NOTICE */ /** END NOTICE */
if(isNative){
/** START USERPOPOUT PATCH */
awaitLogin()
.then(async () => {
let UserPopout = await getModule(e => e.default && e.default.displayName === "FluxContainer(ForwardRef(SubscribeGuildMembersContainer(UserPopout)))")
const userModule = await getModule(e => e.default && e.default.getCurrentUser)
const render1 = new UserPopout.default({userId: userModule.default.getCurrentUser().id, guildId: null, channelId: null, disableUserProfileLink: true}).render()
const PopoutProps = render1.props
const render2 = render1.type.render(PopoutProps, null)
const render3 = new render2.type(render2.props).render()
const UserPopoutComponent = render3.type
if(!UserPopoutComponent)throw new Error(`Couldn't find the UserPopoutComponent component.`)
const render = UserPopoutComponent.prototype.render
UserPopoutComponent.prototype.render = function(){
const returnValue = render.call(this, ...arguments)
try{
returnValue.props.children.props["data-user-id"] = this.props.user.id
}catch(e){
console.error(e)
}
return returnValue
}
})
/** END USERPOPOUT PATCH*/
/** START USERPROFILE PATCH */
awaitLogin()
.then(async () => {
let UserProfile = await getModule(e => e.default && e.default.displayName === "UserProfile")
const userModule = await getModule(e => e.default && e.default.getCurrentUser)
const render1 = new UserProfile.default({
user: userModule.default.getCurrentUser()
}).render()
const render2 = new render1.type(render1.props).render()
const render3 = render2.type.render(render2.props, null)
const render4 = new render3.type(render3.props).render()
const UserProfileComponent = render4.type
if(!UserProfileComponent)throw new Error(`Couldn't find the UserProfileComponent component.`)
const render = UserProfileComponent.prototype.render
UserProfileComponent.prototype.render = function(){
const returnValue = render.call(this, ...arguments)
console.log(returnValue)
try{
returnValue.props.children.props["data-user-id"] = this.props.user.id
}catch(e){
console.error(e)
}
return returnValue
}
})
/** END USERPROFILE PATCH */
}
// TODO: Add in app-notifications / confirmations.
/** START IN-APP NOTIFICATIONS */ /** START IN-APP NOTIFICATIONS */
//getModule(e => true) //getModule(e => true)
/** END IN-APP NOTIFICATIONS */ /** END IN-APP NOTIFICATIONS */
@ -60,4 +117,25 @@ function getModule(filter: (mod:any) => boolean):Promise<any>{
console.error("[LIGHTCORD]", err, filter) console.error("[LIGHTCORD]", err, filter)
}) })
}) })
} }
let hasCompletedLogin = false
let loginPromise:Promise<void>
function awaitLogin():Promise<void>{
if(hasCompletedLogin)return Promise.resolve()
if(loginPromise)return loginPromise
return loginPromise = new Promise((resolve) => {
let isResolved = false
window.Lightcord.DiscordModules.dispatcher.subscribe("CONNECTION_OPEN", (ev) => {
if(isResolved)return
hasCompletedLogin = true
resolve()
isResolved = true
})
})
}
window.Lightcord.DiscordModules.dispatcher.subscribe("LOGOUT", (ev) => {
hasCompletedLogin = false
loginPromise = undefined
})

View File

@ -1,70 +1,71 @@
const path = require("path"); const path = require("path");
const TerserPlugin = require("terser-webpack-plugin") const TerserPlugin = require("terser-webpack-plugin")
module.exports = { module.exports = {
mode: "development", mode: "development",
target: "node", target: "node",
devtool: "inline-source-map", devtool: "inline-source-map",
entry: "./src/index.ts", entry: "./src/index.ts",
output: { output: {
filename: "main.js", filename: "main.js",
path: path.resolve(__dirname, "js"), path: path.resolve(__dirname, "js"),
library: "LightcordApi", library: "LightcordApi",
libraryTarget: "commonjs2" libraryTarget: "commonjs2"
}, },
externals: { externals: {
electron: `electron`, electron: `electron`,
fs: `fs`, fs: `fs`,
path: `path`, path: `path`,
events: `events`, events: `events`,
rimraf: `rimraf`, rimraf: `rimraf`,
yauzl: `yauzl`, yauzl: `yauzl`,
mkdirp: `mkdirp`, mkdirp: `mkdirp`,
request: `request`, request: `request`,
"node-fetch": "node-fetch", "node-fetch": "node-fetch",
"uuid/v1": "uuid/v1", "uuid/v1": "uuid/v1",
"uuid/v4": "uuid/v4" "uuid/v4": "uuid/v4",
}, "powercord/webpack": "powercord/webpack"
resolve: { },
extensions: [".js", ".jsx", ".json", ".ts", ".tsx"], resolve: {
alias: { extensions: [".js", ".jsx", ".json", ".ts", ".tsx"],
"react$": path.resolve(__dirname, "src", "alias", "react.ts"), alias: {
"react-dom$": path.resolve(__dirname, "src", "alias", "react-dom.ts") "react$": path.resolve(__dirname, "src", "alias", "react.ts"),
} "react-dom$": path.resolve(__dirname, "src", "alias", "react-dom.ts")
}, }
module: { },
rules: [{ module: {
test: /\.jsx?$/, rules: [{
loader: "babel-loader", test: /\.jsx?$/,
exclude: /node_modules/, loader: "babel-loader",
query: { exclude: /node_modules/,
presets: [ query: {
["@babel/env", { presets: [
targets: { ["@babel/env", {
node: "12.8.1", targets: {
chrome: "78" node: "12.8.1",
} chrome: "78"
}], "@babel/react" }
] }], "@babel/react"
} ]
}, { }
test: /\.tsx?$/, }, {
use: 'ts-loader', test: /\.tsx?$/,
exclude: /node_modules/, use: 'ts-loader',
}] exclude: /node_modules/,
}, }]
optimization: { },
minimizer: [ optimization: {
new TerserPlugin({ minimizer: [
cache: true, new TerserPlugin({
parallel: true, cache: true,
sourceMap: true, parallel: true,
terserOptions: { sourceMap: true,
mangle: false, terserOptions: {
keep_classnames: true, mangle: false,
keep_fnames: true keep_classnames: true,
} keep_fnames: true
}), }
] }),
} ]
}
}; };

View File

@ -48,7 +48,7 @@ async function privateInit(){
ModuleLoader.get(e => e.getCurrentHub)[0].getCurrentHub().getClient().getOptions().enabled = false ModuleLoader.get(e => e.getCurrentHub)[0].getCurrentHub().getClient().getOptions().enabled = false
// setting react in require cache // setting react in require cache
const React = ModuleLoader.get(e => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].map(c => !!e[c]).includes(false))[0] const React = ModuleLoader.get(e => !["Component", "PureComponent", "Children", "createElement", "cloneElement"].find(k => !e[k]))[0]
window.React = React window.React = React
const ReactDOM = ModuleLoader.get(e => e.findDOMNode)[0] const ReactDOM = ModuleLoader.get(e => e.findDOMNode)[0]
@ -278,7 +278,7 @@ async function privateInit(){
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme) DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
}) })
require("lightcordapi/js/main.js") require("lightcordapi/js/main.min.js")
/* /*
if(shouldShowPrompt){ if(shouldShowPrompt){

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,3 @@
process.once('loaded', () => {
console.log("sltsv")
})

View File

@ -14,9 +14,11 @@ var _electron = require('electron');
var _appFeatures = require('./appFeatures'); var _appFeatures = require('./appFeatures');
var _mainScreen = require('./mainScreen'); var _mainScreen = require('./mainScreen');
const { join } = require('path');
const MIN_POPOUT_WIDTH = 320; const MIN_POPOUT_WIDTH = 320;
const MIN_POPOUT_HEIGHT = 180; const MIN_POPOUT_HEIGHT = 180;
/** @type {Electron.BrowserWindowConstructorOptions} */
const DEFAULT_POPOUT_OPTIONS = { const DEFAULT_POPOUT_OPTIONS = {
title: 'Lightcord Popout', title: 'Lightcord Popout',
backgroundColor: '#2f3136', backgroundColor: '#2f3136',
@ -29,7 +31,8 @@ const DEFAULT_POPOUT_OPTIONS = {
webPreferences: { webPreferences: {
nodeIntegration: false, nodeIntegration: false,
nativeWindowOpen: true nativeWindowOpen: true
} },
icon: join(__dirname, 'discord.png')
}; };
const features = (0, _appFeatures.getFeatures)(); const features = (0, _appFeatures.getFeatures)();

View File

@ -13,8 +13,8 @@
"build:electron_linux": "electron-packager ./distApp --ignore=\"(distApp|builds|\\.ts|\\.dll)\" --arch=x64 --protocol=discord --platform=\"linux\" --out=builds --icon=app.ico --executable-name=\"Lightcord\" --asar.unpack=*.{node,so.4} --overwrite", "build:electron_linux": "electron-packager ./distApp --ignore=\"(distApp|builds|\\.ts|\\.dll)\" --arch=x64 --protocol=discord --platform=\"linux\" --out=builds --icon=app.ico --executable-name=\"Lightcord\" --asar.unpack=*.{node,so.4} --overwrite",
"build:minify": "node build.js", "build:minify": "node build.js",
"build:after": "node afterbuild.js", "build:after": "node afterbuild.js",
"devInstall": "npm i -g --arch=ia32 electron@8.4.0 && npm i -g typescript && npm i --save-dev @types/node@12.12.39 && npm i --save-dev --arch=ia32 electron@8.4.0 && node installSubModules.js && echo \"Everything is installed. You should be able to do `npm run test` to compile everything and launch.\"", "devInstall": "npm i --save-dev --arch=ia32 electron@8.4.0 && node installSubModules.js && echo \"Everything is installed. You should be able to do `npm run test` to compile everything and launch.\"",
"devInstall:64": "npm i -g --arch=x64 electron@8.4.0 && npm i -g typescript && npm i --save-dev @types/node@12.12.39 && npm i --save-dev --arch=x64 electron@8.4.0 && node installSubModules.js && echo \"Everything is installed. You should be able to do `npm run test` to compile everything and launch.\"" "devInstall:64": "npm i --save-dev --arch=x64 electron@8.4.0 && node installSubModules.js && echo \"Everything is installed. You should be able to do `npm run test` to compile everything and launch.\""
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -34,7 +34,7 @@
"@types/auto-launch": "^5.0.1", "@types/auto-launch": "^5.0.1",
"@types/electron-devtools-installer": "^2.2.0", "@types/electron-devtools-installer": "^2.2.0",
"@types/mkdirp": "^1.0.0", "@types/mkdirp": "^1.0.0",
"@types/node": "^12.12.39", "@types/node": "12.12.39",
"@types/rimraf": "^3.0.0", "@types/rimraf": "^3.0.0",
"@types/uuid": "^8.0.0", "@types/uuid": "^8.0.0",
"@types/yauzl": "^2.9.1", "@types/yauzl": "^2.9.1",