From 68b989462e986bcd99380d292e0940ea7d52508d Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Thu, 27 Feb 2025 07:25:27 +0800 Subject: [PATCH 1/7] backend restructure --- .gitignore | 1 + backend/filesystem/dialog.go | 87 +++++++++++++++++++ backend/filesystem/file_manager.go | 54 ++++++++++++ backend/obfuscator/config.go | 83 ++++++++++++++++++ backend/obfuscator/obfuscator.go | 44 ++++++++++ frontend/package.json.md5 | 2 +- frontend/wailsjs/go/filesystem/Dialog.d.ts | 13 +++ frontend/wailsjs/go/filesystem/Dialog.js | 23 +++++ .../wailsjs/go/filesystem/FileManager.d.ts | 9 ++ frontend/wailsjs/go/filesystem/FileManager.js | 15 ++++ frontend/wailsjs/go/models.ts | 31 +++++++ .../wailsjs/go/obfuscator/obfuscator.d.ts | 10 +++ frontend/wailsjs/go/obfuscator/obfuscator.js | 15 ++++ main.go | 21 ++++- 14 files changed, 403 insertions(+), 5 deletions(-) create mode 100644 backend/filesystem/dialog.go create mode 100644 backend/filesystem/file_manager.go create mode 100644 backend/obfuscator/config.go create mode 100644 backend/obfuscator/obfuscator.go create mode 100755 frontend/wailsjs/go/filesystem/Dialog.d.ts create mode 100755 frontend/wailsjs/go/filesystem/Dialog.js create mode 100755 frontend/wailsjs/go/filesystem/FileManager.d.ts create mode 100755 frontend/wailsjs/go/filesystem/FileManager.js mode change 100644 => 100755 frontend/wailsjs/go/models.ts create mode 100755 frontend/wailsjs/go/obfuscator/obfuscator.d.ts create mode 100755 frontend/wailsjs/go/obfuscator/obfuscator.js diff --git a/.gitignore b/.gitignore index 129d522..253ef93 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/bin node_modules frontend/dist +.idea/ diff --git a/backend/filesystem/dialog.go b/backend/filesystem/dialog.go new file mode 100644 index 0000000..40c6920 --- /dev/null +++ b/backend/filesystem/dialog.go @@ -0,0 +1,87 @@ +package filesystem + +import ( + "context" + "errors" + "github.com/wailsapp/wails/v2/pkg/runtime" + "io/fs" + "os/exec" + "path/filepath" + goRuntime "runtime" + "strings" +) + +type Dialog struct { + ctx context.Context +} + +func NewDialog() *Dialog { + return &Dialog{} +} + +func (d *Dialog) SetContext(ctx context.Context) { + d.ctx = ctx +} + +func (d *Dialog) OpenMultipleFilesDialog() ([]string, error) { + return runtime.OpenMultipleFilesDialog(d.ctx, runtime.OpenDialogOptions{ + Title: "Select file(s)", + Filters: []runtime.FileFilter{ + {DisplayName: "JavaScript", Pattern: "*.js"}, + {DisplayName: "PHP", Pattern: "*.php"}, + {DisplayName: "All Files", Pattern: "*"}, + }, + ShowHiddenFiles: true, + }) +} + +func (d *Dialog) OpenDirectoryDialog() ([]string, error) { + path, err := runtime.OpenDirectoryDialog(d.ctx, runtime.OpenDialogOptions{ + Title: "Select folder", + }) + if err != nil { + return nil, err + } + + if path == "" { + return nil, errors.New("could not open folder") + } + + var files []string + err = filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if !d.IsDir() && (strings.HasSuffix(path, ".js") || strings.HasSuffix(path, ".php")) { + files = append(files, path) + } + + return nil + }) + return files, err +} + +func (d *Dialog) OpenFileLocation(path string) error { + currOS := goRuntime.GOOS + command, ok := map[string]string{ + "windows": "explorer", + "darwin": "open", + "linux": "xdg-open", + }[currOS] + if !ok { + return errors.New("unsupported OS: " + currOS) + } + + return exec.Command(command, filepath.Dir(path)).Run() +} + +func (d *Dialog) MessageInfoDialog(title string, message string) error { + _, err := runtime.MessageDialog(d.ctx, runtime.MessageDialogOptions{ + Title: title, + Message: message, + Type: runtime.InfoDialog, + }) + + return err +} diff --git a/backend/filesystem/file_manager.go b/backend/filesystem/file_manager.go new file mode 100644 index 0000000..49c0bfb --- /dev/null +++ b/backend/filesystem/file_manager.go @@ -0,0 +1,54 @@ +package filesystem + +import ( + "context" + "fmt" + "os" + "path/filepath" +) + +type FileManager struct { + ctx context.Context +} + +func NewFileManager() *FileManager { + return &FileManager{} +} + +func (f *FileManager) SetContext(ctx context.Context) { + f.ctx = ctx +} + +func (f *FileManager) ReadFile(path string) (string, error) { + contents, err := os.ReadFile(path) + if err != nil { + return "", err + } + + return string(contents), nil +} + +func (f *FileManager) WriteFile(path string, content string) error { + if _, err := os.Stat(path); os.IsNotExist(err) { + if err = os.WriteFile(path, []byte(content), 0644); err != nil { + return err + } + + return nil + } + + extension := filepath.Ext(path) + filename := path[:len(path)-len(extension)] + index := 1 + for { + path = fmt.Sprintf("%s_%d%s", filename, index, extension) + if _, ok := os.Stat(path); os.IsNotExist(ok) { + if err := os.WriteFile(path, []byte(content), 0644); err != nil { + return err + } + + return nil + } + index++ + } +} diff --git a/backend/obfuscator/config.go b/backend/obfuscator/config.go new file mode 100644 index 0000000..5ef9fea --- /dev/null +++ b/backend/obfuscator/config.go @@ -0,0 +1,83 @@ +package obfuscator + +import ( + "encoding/json" + "log" + "os" + "path/filepath" +) + +type Config struct { + SingleLineOutput bool `json:"single_line_output"` + StringLiteral bool `json:"string_literal"` + LoopStatement bool `json:"loop_statement"` + IfStatement bool `json:"if_statement"` + ConstantName bool `json:"constant_name"` + VariableName bool `json:"variable_name"` + FunctionName bool `json:"function_name"` + RemoveComments bool `json:"remove_comments"` + path string +} + +func NewConfig() Config { + var config Config + + err := config.load() + if os.IsNotExist(err) { + if err = config.save(); err != nil { + log.Fatal(err) + } + } else if err != nil { + log.Fatal(err) + } + + return config +} + +func (config *Config) load() error { + configDir, err := os.UserConfigDir() + if err != nil { + return err + } + + appConfigDir := filepath.Join(configDir, "hyperion") + _, err = os.Stat(appConfigDir) + if os.IsNotExist(err) { + if err = os.MkdirAll(appConfigDir, os.ModePerm); err != nil { + return err + } + } + + config.path = filepath.Join(appConfigDir, "config.json") + if _, err = os.Stat(config.path); err != nil { + return err + } + + data, err := os.ReadFile(config.path) + if err != nil { + return err + } + + if err = json.Unmarshal(data, &config); err != nil { + return err + } + + return nil +} + +func (config *Config) save() error { + data, err := json.MarshalIndent(config, "", " ") + if err != nil { + return err + } + + return os.WriteFile(config.path, data, os.ModePerm) +} + +func (config *Config) Save(c Config) { + log.Println("Saving obfuscation configuration", c) +} + +func (config *Config) GetConfig() Config { + return *config +} diff --git a/backend/obfuscator/obfuscator.go b/backend/obfuscator/obfuscator.go new file mode 100644 index 0000000..9dcfdec --- /dev/null +++ b/backend/obfuscator/obfuscator.go @@ -0,0 +1,44 @@ +package obfuscator + +import ( + "context" + "errors" + "log" + "path/filepath" +) + +type Obfuscator interface { + SetContext(ctx context.Context) + Config() Config + Obfuscate(path string) (string, error) +} + +type obfuscator struct { + ctx context.Context + config Config +} + +func NewObfuscator() Obfuscator { + return &obfuscator{ + config: NewConfig(), + } +} + +func (o *obfuscator) SetContext(ctx context.Context) { + o.ctx = ctx +} + +func (o *obfuscator) Obfuscate(path string) (string, error) { + if path == "" { + return "", errors.New("empty path") + } + + extension := filepath.Ext(path) + log.Println(extension) + + return "", nil +} + +func (o *obfuscator) Config() Config { + return o.config +} diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 0ab9858..6d22033 100644 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -e7a6ebe68b6ebb625e23cd9bc17c6d58 \ No newline at end of file +2b14923900ddcaba950113356b5730d8 \ No newline at end of file diff --git a/frontend/wailsjs/go/filesystem/Dialog.d.ts b/frontend/wailsjs/go/filesystem/Dialog.d.ts new file mode 100755 index 0000000..018f75e --- /dev/null +++ b/frontend/wailsjs/go/filesystem/Dialog.d.ts @@ -0,0 +1,13 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {context} from '../models'; + +export function MessageInfoDialog(arg1:string,arg2:string):Promise; + +export function OpenDirectoryDialog():Promise>; + +export function OpenFileLocation(arg1:string):Promise; + +export function OpenMultipleFilesDialog():Promise>; + +export function SetContext(arg1:context.Context):Promise; diff --git a/frontend/wailsjs/go/filesystem/Dialog.js b/frontend/wailsjs/go/filesystem/Dialog.js new file mode 100755 index 0000000..ccc52a0 --- /dev/null +++ b/frontend/wailsjs/go/filesystem/Dialog.js @@ -0,0 +1,23 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function MessageInfoDialog(arg1, arg2) { + return window['go']['filesystem']['Dialog']['MessageInfoDialog'](arg1, arg2); +} + +export function OpenDirectoryDialog() { + return window['go']['filesystem']['Dialog']['OpenDirectoryDialog'](); +} + +export function OpenFileLocation(arg1) { + return window['go']['filesystem']['Dialog']['OpenFileLocation'](arg1); +} + +export function OpenMultipleFilesDialog() { + return window['go']['filesystem']['Dialog']['OpenMultipleFilesDialog'](); +} + +export function SetContext(arg1) { + return window['go']['filesystem']['Dialog']['SetContext'](arg1); +} diff --git a/frontend/wailsjs/go/filesystem/FileManager.d.ts b/frontend/wailsjs/go/filesystem/FileManager.d.ts new file mode 100755 index 0000000..6bc4775 --- /dev/null +++ b/frontend/wailsjs/go/filesystem/FileManager.d.ts @@ -0,0 +1,9 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {context} from '../models'; + +export function ReadFile(arg1:string):Promise; + +export function SetContext(arg1:context.Context):Promise; + +export function WriteFile(arg1:string,arg2:string):Promise; diff --git a/frontend/wailsjs/go/filesystem/FileManager.js b/frontend/wailsjs/go/filesystem/FileManager.js new file mode 100755 index 0000000..0b79b70 --- /dev/null +++ b/frontend/wailsjs/go/filesystem/FileManager.js @@ -0,0 +1,15 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function ReadFile(arg1) { + return window['go']['filesystem']['FileManager']['ReadFile'](arg1); +} + +export function SetContext(arg1) { + return window['go']['filesystem']['FileManager']['SetContext'](arg1); +} + +export function WriteFile(arg1, arg2) { + return window['go']['filesystem']['FileManager']['WriteFile'](arg1, arg2); +} diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts old mode 100644 new mode 100755 index 44a016c..c6e4297 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -19,3 +19,34 @@ export namespace main { } +export namespace obfuscator { + + export class Config { + single_line_output: boolean; + string_literal: boolean; + loop_statement: boolean; + if_statement: boolean; + constant_name: boolean; + variable_name: boolean; + function_name: boolean; + remove_comments: boolean; + + static createFrom(source: any = {}) { + return new Config(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.single_line_output = source["single_line_output"]; + this.string_literal = source["string_literal"]; + this.loop_statement = source["loop_statement"]; + this.if_statement = source["if_statement"]; + this.constant_name = source["constant_name"]; + this.variable_name = source["variable_name"]; + this.function_name = source["function_name"]; + this.remove_comments = source["remove_comments"]; + } + } + +} + diff --git a/frontend/wailsjs/go/obfuscator/obfuscator.d.ts b/frontend/wailsjs/go/obfuscator/obfuscator.d.ts new file mode 100755 index 0000000..5fb791f --- /dev/null +++ b/frontend/wailsjs/go/obfuscator/obfuscator.d.ts @@ -0,0 +1,10 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {obfuscator} from '../models'; +import {context} from '../models'; + +export function Config():Promise; + +export function Obfuscate(arg1:string):Promise; + +export function SetContext(arg1:context.Context):Promise; diff --git a/frontend/wailsjs/go/obfuscator/obfuscator.js b/frontend/wailsjs/go/obfuscator/obfuscator.js new file mode 100755 index 0000000..42ceb6e --- /dev/null +++ b/frontend/wailsjs/go/obfuscator/obfuscator.js @@ -0,0 +1,15 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function Config() { + return window['go']['obfuscator']['obfuscator']['Config'](); +} + +export function Obfuscate(arg1) { + return window['go']['obfuscator']['obfuscator']['Obfuscate'](arg1); +} + +export function SetContext(arg1) { + return window['go']['obfuscator']['obfuscator']['SetContext'](arg1); +} diff --git a/main.go b/main.go index 51a57f3..cc29848 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,17 @@ package main import ( + "context" "embed" - "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/assetserver" "github.com/wailsapp/wails/v2/pkg/options/linux" "github.com/wailsapp/wails/v2/pkg/options/mac" "github.com/wailsapp/wails/v2/pkg/options/windows" + fs "hyperion/backend/filesystem" + ob "hyperion/backend/obfuscator" + "log" ) //go:embed all:frontend/dist @@ -18,6 +21,10 @@ func main() { // Create an instance of the app structure app := NewApp() + file := fs.NewFileManager() + dialog := fs.NewDialog() + obfuscator := ob.NewObfuscator() + // Create application with options err := wails.Run(&options.App{ Title: "hyperion", @@ -29,9 +36,15 @@ func main() { Assets: assets, }, BackgroundColour: &options.RGBA{R: 0, G: 0, B: 0, A: 0}, - OnStartup: app.startup, + OnStartup: func(ctx context.Context) { + app.startup(ctx) + file.SetContext(ctx) + dialog.SetContext(ctx) + obfuscator.SetContext(ctx) + }, Bind: []interface{}{ - app, + app, dialog, + file, obfuscator, }, Windows: &windows.Options{ WebviewIsTransparent: true, @@ -56,6 +69,6 @@ func main() { }) if err != nil { - println("Error:", err.Error()) + log.Fatal(err) } } From bc3f8692679deeeda9cfca0c59970ee5bc08f769 Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Thu, 27 Feb 2025 07:28:09 +0800 Subject: [PATCH 2/7] push test --- backend/obfuscator/obfuscator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/obfuscator/obfuscator.go b/backend/obfuscator/obfuscator.go index 9dcfdec..a54df2d 100644 --- a/backend/obfuscator/obfuscator.go +++ b/backend/obfuscator/obfuscator.go @@ -36,7 +36,7 @@ func (o *obfuscator) Obfuscate(path string) (string, error) { extension := filepath.Ext(path) log.Println(extension) - return "", nil + return "really", nil } func (o *obfuscator) Config() Config { From f6537ff03ca3f61aba47cf4672a03fa2bc2bb819 Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Thu, 6 Mar 2025 08:02:28 +0800 Subject: [PATCH 3/7] obfuscator interface --- backend/obfuscator/config.go | 2 + backend/obfuscator/js/js.go | 38 +++++++ backend/obfuscator/obfuscator.go | 102 ++++++++++++++++--- backend/obfuscator/obfuscator_test.go | 19 ++++ frontend/wailsjs/go/obfuscator/obfuscator.js | 6 +- go.mod | 8 +- go.sum | 1 + main.go | 2 +- 8 files changed, 157 insertions(+), 21 deletions(-) create mode 100644 backend/obfuscator/js/js.go create mode 100644 backend/obfuscator/obfuscator_test.go diff --git a/backend/obfuscator/config.go b/backend/obfuscator/config.go index 5ef9fea..1701a3b 100644 --- a/backend/obfuscator/config.go +++ b/backend/obfuscator/config.go @@ -31,6 +31,8 @@ func NewConfig() Config { log.Fatal(err) } + log.Println("Hyperion config:", config.path) + return config } diff --git a/backend/obfuscator/js/js.go b/backend/obfuscator/js/js.go new file mode 100644 index 0000000..82a4ce4 --- /dev/null +++ b/backend/obfuscator/js/js.go @@ -0,0 +1,38 @@ +package js + +type Obfuscation struct{} + +func (o Obfuscation) SingleLine(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RefactorLoopStatement(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RefactorIfStatement(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RenameVariable(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RenameConstant(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RenameFunction(code string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (o Obfuscation) RemoveComment(code string) (string, error) { + //TODO implement me + panic("implement me") +} diff --git a/backend/obfuscator/obfuscator.go b/backend/obfuscator/obfuscator.go index a54df2d..c235665 100644 --- a/backend/obfuscator/obfuscator.go +++ b/backend/obfuscator/obfuscator.go @@ -3,42 +3,112 @@ package obfuscator import ( "context" "errors" - "log" + "hyperion/backend/obfuscator/js" + "os" "path/filepath" ) -type Obfuscator interface { - SetContext(ctx context.Context) - Config() Config - Obfuscate(path string) (string, error) -} - -type obfuscator struct { +type Obfuscator struct { ctx context.Context config Config } -func NewObfuscator() Obfuscator { - return &obfuscator{ - config: NewConfig(), +func NewObfuscator(config Config) *Obfuscator { + return &Obfuscator{ + config: config, + } +} + +type IObfuscation interface { + SingleLine(code string) (string, error) + RefactorLoopStatement(code string) (string, error) + RefactorIfStatement(code string) (string, error) + RenameVariable(code string) (string, error) + RenameConstant(code string) (string, error) + RenameFunction(code string) (string, error) + RemoveComment(code string) (string, error) +} + +func GetObfuscation(extension string) IObfuscation { + switch extension { + case "js": + return js.Obfuscation{} + default: + return nil } } -func (o *obfuscator) SetContext(ctx context.Context) { +func (o *Obfuscator) SetContext(ctx context.Context) { o.ctx = ctx } -func (o *obfuscator) Obfuscate(path string) (string, error) { +func (o *Obfuscator) Obfuscate(path string) (string, error) { if path == "" { return "", errors.New("empty path") } + b, err := os.ReadFile(path) + if err != nil { + return "", err + } + + content := string(b) + extension := filepath.Ext(path) - log.Println(extension) + obfuscation := GetObfuscation(extension) + + if o.config.LoopStatement { + content, err = obfuscation.RefactorLoopStatement(content) + if err != nil { + return content, err + } + } + + if o.config.IfStatement { + content, err = obfuscation.RefactorIfStatement(content) + if err != nil { + return content, err + } + } + + if o.config.VariableName { + content, err = obfuscation.RenameVariable(content) + if err != nil { + return content, err + } + } + + if o.config.ConstantName { + content, err = obfuscation.RenameConstant(content) + if err != nil { + return content, err + } + } + + if o.config.FunctionName { + content, err = obfuscation.RenameFunction(content) + if err != nil { + return content, err + } + } + + if o.config.RemoveComments { + content, err = obfuscation.RemoveComment(content) + if err != nil { + return content, err + } + } + + if o.config.SingleLineOutput { + content, err = obfuscation.SingleLine(content) + if err != nil { + return content, err + } + } - return "really", nil + return content, nil } -func (o *obfuscator) Config() Config { +func (o *Obfuscator) Config() Config { return o.config } diff --git a/backend/obfuscator/obfuscator_test.go b/backend/obfuscator/obfuscator_test.go new file mode 100644 index 0000000..ee20918 --- /dev/null +++ b/backend/obfuscator/obfuscator_test.go @@ -0,0 +1,19 @@ +package obfuscator_test + +import ( + "github.com/stretchr/testify/assert" + obf "hyperion/backend/obfuscator" + "testing" +) + +func TestNewObfuscator(t *testing.T) { + config := obf.Config{} + obfuscator := obf.NewObfuscator(config) + + assert.NotNil(t, obfuscator) + assert.IsType(t, obf.Obfuscator{}, obfuscator) +} + +func Test_obfuscator_Obfuscate(t *testing.T) { + +} diff --git a/frontend/wailsjs/go/obfuscator/obfuscator.js b/frontend/wailsjs/go/obfuscator/obfuscator.js index 42ceb6e..0077875 100755 --- a/frontend/wailsjs/go/obfuscator/obfuscator.js +++ b/frontend/wailsjs/go/obfuscator/obfuscator.js @@ -3,13 +3,13 @@ // This file is automatically generated. DO NOT EDIT export function Config() { - return window['go']['obfuscator']['obfuscator']['Config'](); + return window['go']['obfuscator']['Obfuscator']['Config'](); } export function Obfuscate(arg1) { - return window['go']['obfuscator']['obfuscator']['Obfuscate'](arg1); + return window['go']['obfuscator']['Obfuscator']['Obfuscate'](arg1); } export function SetContext(arg1) { - return window['go']['obfuscator']['obfuscator']['SetContext'](arg1); + return window['go']['obfuscator']['Obfuscator']['SetContext'](arg1); } diff --git a/go.mod b/go.mod index f129278..2bfd223 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,14 @@ go 1.21 toolchain go1.23.4 -require github.com/wailsapp/wails/v2 v2.9.2 +require ( + github.com/stretchr/testify v1.8.4 + github.com/wailsapp/wails/v2 v2.9.2 +) require ( github.com/bep/debounce v1.2.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/uuid v1.3.0 // indirect @@ -22,6 +26,7 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/samber/lo v1.38.1 // indirect github.com/tkrajina/go-reflector v0.5.6 // indirect @@ -34,6 +39,7 @@ require ( golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) // replace github.com/wailsapp/wails/v2 v2.9.2 => /Users/iqbaleff214/Developments/go/pkg/mod diff --git a/go.sum b/go.sum index 6ed0576..ebccd33 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index cc29848..efeadec 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ func main() { file := fs.NewFileManager() dialog := fs.NewDialog() - obfuscator := ob.NewObfuscator() + obfuscator := ob.NewObfuscator(ob.NewConfig()) // Create application with options err := wails.Run(&options.App{ From 56d9255374783eff446d25a40950c5ba6407d257 Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Sat, 8 Mar 2025 13:36:05 +0800 Subject: [PATCH 4/7] obfuscator javascript --- backend/obfuscator/examples/example.js | 74 +++++++++++++++++ backend/obfuscator/js/js.go | 109 +++++++++++++++++++++---- backend/obfuscator/js/js_test.go | 57 +++++++++++++ backend/obfuscator/obfuscator.go | 31 +++---- backend/obfuscator/obfuscator_test.go | 14 +++- backend/util/name_generator.go | 28 +++++++ backend/util/name_generator_test.go | 28 +++++++ 7 files changed, 312 insertions(+), 29 deletions(-) create mode 100644 backend/obfuscator/examples/example.js create mode 100644 backend/obfuscator/js/js_test.go create mode 100644 backend/util/name_generator.go create mode 100644 backend/util/name_generator_test.go diff --git a/backend/obfuscator/examples/example.js b/backend/obfuscator/examples/example.js new file mode 100644 index 0000000..b553eff --- /dev/null +++ b/backend/obfuscator/examples/example.js @@ -0,0 +1,74 @@ +const constantName = 'constantName'; +const CONSTANT_NAME = 'CONSTANT_NAME'; +const constant_name = 'constant_name'; +const ConstantName = 'ConstantName'; + +let variableName1 = 'VARIABLE_NAME_1'; +var variableName2 = 'VARIABLE_NAME_2'; +let variableName3, variableName4; +var variableName5, variableName6; +let variableName7,variableName8 ,variableName9 , variableName10; + +// REGULAR FUNCTION WITHOUT RETURN +function functionName1 () { + // constantName + // console.log("DECEPTION: constantNameCONSTANT_NAME constant_name-ConstantName"); + console.log("DECEPTION: constantNameCONSTANT_NAME constant_name-ConstantName"); // Just string + console.log(`DECEPTION: ${constantName} ${CONSTANT_NAME}`); // This is constant, bro + console.log('DECEPTION: ${CONSTANT_NAME}'); // String + console.log("DECEPTION: ${constant_name}"); // String again + console.log(constantName, CONSTANT_NAME, constant_name, ConstantName); +} + +// ARROW FUNCTION WITHOUT RETURN +const functionName2 = () => { + // variableName6 + // console.log("DECEPTION: variableName1 variableName6variableName4"); + console.log("DECEPTION: variableName3 variableName2variableName5"); // Just string + console.log(`DECEPTION: ${variableName6} ${variableName2}`); // This is variable, bro + console.log('DECEPTION: ${variableName6}'); // String + console.log("DECEPTION: ${variableName6}"); // String again + console.log(variableName6, variableName5, variableName2, variableName3, variableName4); +}; + +/** + * functionName3 - regular function to sum parameters + * @param params1 {int} + * @param params2 {int} + * @returns {int} + */ +function functionName3 (params1, params2) { + return params1 + params2; +} + +/** + * functionName4 - arrow function to sum parameters + * @param params1 + * @param params2 + * @returns {*} + */ +const functionName4 = (params1, params2) => params1 + params2; + +// ARROW FUNCTION WITHOUT PARENTHESES AND BRACKETS +const functionName5 = params => console.log(params); + +// REGULAR FUNCTION WITH SPREAD PARAMETER +function functionName6 (...params) { + for (const param of params) { + console.log(param); + } +} + +functionName1(); +functionName2(); +const functionName3Result = functionName3(10, 20); +let functionName4Result = functionName4(20, 10); +functionName5('DONE'); +functionName6('A', 'N', 'J', 'A', 'Y'); + +/** LAST STATEMENT **/ +if (functionName3Result === functionName4Result) { + console.log('FUNCTION RESULT IS IDENTICAL'); +} + + diff --git a/backend/obfuscator/js/js.go b/backend/obfuscator/js/js.go index 82a4ce4..5b6abe6 100644 --- a/backend/obfuscator/js/js.go +++ b/backend/obfuscator/js/js.go @@ -1,38 +1,119 @@ package js +import ( + "fmt" + "hyperion/backend/util" + "regexp" + "strings" +) + type Obfuscation struct{} +// SingleLine +// TODO: self-explanatory func (o Obfuscation) SingleLine(code string) (string, error) { - //TODO implement me - panic("implement me") + return code, nil } +// RefactorLoopStatement +// TODO: self-explanatory func (o Obfuscation) RefactorLoopStatement(code string) (string, error) { - //TODO implement me - panic("implement me") + return code, nil } +// RefactorIfStatement +// TODO: self-explanatory func (o Obfuscation) RefactorIfStatement(code string) (string, error) { - //TODO implement me - panic("implement me") + return code, nil } +// RenameVariable +// TODO: +// - Jangan sampai string yang memiliki kata yang sama dengan variable berubah +// - String yang memuat kata yang sama dengan variable bisa terhindar dari perubahan, akan tetapi malah semua variable tidak berubah namanya func (o Obfuscation) RenameVariable(code string) (string, error) { - //TODO implement me - panic("implement me") + varRegex := regexp.MustCompile(`\b(?Plet|var)\s+(?P[a-zA-Z_]\w*(?:\s*,\s*[a-zA-Z_]\w*)*)`) + stringRegex := regexp.MustCompile(`"(?:\\.|[^"])*?"|'(?:\\.|[^'])*?'|` + "`" + `(?:\\.|[^` + "`" + `])*?` + "`") + templateRegex := regexp.MustCompile(`\$\{([a-zA-Z_]\w*)\}`) + + varMapping := make(map[string]string) + code = varRegex.ReplaceAllStringFunc(code, func(match string) string { + parts := varRegex.FindStringSubmatch(match) + keyword, varNames := parts[1], parts[2] + + names := strings.Split(varNames, ",") + for i, name := range names { + name = strings.TrimSpace(name) + if _, exists := varMapping[name]; !exists { + varMapping[name] = util.GenerateName("_v") + } + names[i] = varMapping[name] + } + + return keyword + " " + strings.Join(names, ", ") + }) + + matches := stringRegex.FindAllStringIndex(code, -1) + + code = templateRegex.ReplaceAllStringFunc(code, func(match string) string { + groups := templateRegex.FindStringSubmatch(match) + oldName := groups[1] + + if newName, exists := varMapping[oldName]; exists { + return fmt.Sprintf("${%s}", newName) + } + return match + }) + + for oldName, newName := range varMapping { + code = regexp.MustCompile(`\b`+oldName+`\b`).ReplaceAllStringFunc(code, func(match string) string { + for _, pos := range matches { + if pos[0] <= strings.Index(code, match) && strings.Index(code, match) <= pos[1] { + return match + } + } + return newName + }) + } + + return code, nil } +// RenameConstant +// TODO: func (o Obfuscation) RenameConstant(code string) (string, error) { - //TODO implement me - panic("implement me") + rgx := regexp.MustCompile(`(?m)(const\s+)([a-zA-Z_][a-zA-Z0-9_]*)(\s*=)`) + matches := rgx.FindAllStringSubmatch(code, -1) + + replacements := make(map[string]string) + + for _, match := range matches { + oldName := match[2] + if _, exists := replacements[oldName]; !exists { + replacements[oldName] = util.GenerateName("_c") + } + } + + for oldName, newName := range replacements { + code = strings.ReplaceAll(code, oldName, newName) + } + + return code, nil } +// RenameFunction +// TODO: self-explanatory func (o Obfuscation) RenameFunction(code string) (string, error) { - //TODO implement me - panic("implement me") + return code, nil } +// RemoveComment - remove any comments from code func (o Obfuscation) RemoveComment(code string) (string, error) { - //TODO implement me - panic("implement me") + singleLine := regexp.MustCompile(`//.*`) + code = singleLine.ReplaceAllString(code, "") + + multiLine := regexp.MustCompile(`/\*[\s\S]*?\*/`) + code = multiLine.ReplaceAllString(code, "") + + return code, nil } diff --git a/backend/obfuscator/js/js_test.go b/backend/obfuscator/js/js_test.go new file mode 100644 index 0000000..e44d467 --- /dev/null +++ b/backend/obfuscator/js/js_test.go @@ -0,0 +1,57 @@ +package js_test + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "hyperion/backend/obfuscator/js" + "os" + "path/filepath" + "strings" + "testing" +) + +var obfuscator = js.Obfuscation{} +var code string + +func init() { + relativePath := "../examples/example.js" + absolutePath, err := filepath.Abs(relativePath) + if err != nil { + panic(err) + } + + b, err := os.ReadFile(absolutePath) + if err != nil { + panic(err) + } + + code = string(b) +} + +func TestObfuscation_RemoveComment(t *testing.T) { + content, err := obfuscator.RemoveComment(code) + if err != nil { + t.Fatal(err) + } + + assert.Zero(t, strings.Count(content, "//"), "Expected code to not have single-line comments") + assert.Zero(t, strings.Count(content, "/**"), "Expected code to not have multi-line comments") +} + +func TestObfuscation_RenameVariable(t *testing.T) { + content, err := obfuscator.RenameVariable(code) + if err != nil { + t.Fatal(err) + } + + fmt.Println(content) +} + +func TestObfuscation_RenameConstant(t *testing.T) { + content, err := obfuscator.RenameConstant(code) + if err != nil { + t.Fatal(err) + } + + fmt.Println(content) +} diff --git a/backend/obfuscator/obfuscator.go b/backend/obfuscator/obfuscator.go index c235665..16391bb 100644 --- a/backend/obfuscator/obfuscator.go +++ b/backend/obfuscator/obfuscator.go @@ -29,12 +29,12 @@ type IObfuscation interface { RemoveComment(code string) (string, error) } -func GetObfuscation(extension string) IObfuscation { +func GetObfuscation(extension string) (IObfuscation, error) { switch extension { case "js": - return js.Obfuscation{} + return js.Obfuscation{}, nil default: - return nil + return nil, errors.New("unknown obfuscation extension") } } @@ -55,17 +55,13 @@ func (o *Obfuscator) Obfuscate(path string) (string, error) { content := string(b) extension := filepath.Ext(path) - obfuscation := GetObfuscation(extension) - - if o.config.LoopStatement { - content, err = obfuscation.RefactorLoopStatement(content) - if err != nil { - return content, err - } + obfuscation, err := GetObfuscation(extension) + if err != nil { + return "", err } - if o.config.IfStatement { - content, err = obfuscation.RefactorIfStatement(content) + if o.config.RemoveComments { + content, err = obfuscation.RemoveComment(content) if err != nil { return content, err } @@ -92,8 +88,15 @@ func (o *Obfuscator) Obfuscate(path string) (string, error) { } } - if o.config.RemoveComments { - content, err = obfuscation.RemoveComment(content) + if o.config.IfStatement { + content, err = obfuscation.RefactorIfStatement(content) + if err != nil { + return content, err + } + } + + if o.config.LoopStatement { + content, err = obfuscation.RefactorLoopStatement(content) if err != nil { return content, err } diff --git a/backend/obfuscator/obfuscator_test.go b/backend/obfuscator/obfuscator_test.go index ee20918..ed3a4b8 100644 --- a/backend/obfuscator/obfuscator_test.go +++ b/backend/obfuscator/obfuscator_test.go @@ -1,19 +1,31 @@ package obfuscator_test import ( + "embed" + "fmt" "github.com/stretchr/testify/assert" obf "hyperion/backend/obfuscator" "testing" ) +//go:embed examples/* +var Examples embed.FS + func TestNewObfuscator(t *testing.T) { config := obf.Config{} obfuscator := obf.NewObfuscator(config) assert.NotNil(t, obfuscator) - assert.IsType(t, obf.Obfuscator{}, obfuscator) + assert.IsType(t, &obf.Obfuscator{}, obfuscator) } func Test_obfuscator_Obfuscate(t *testing.T) { + files, err := Examples.ReadDir("examples") + if err != nil { + t.Fatal(err) + } + for _, file := range files { + fmt.Println(file.Name()) + } } diff --git a/backend/util/name_generator.go b/backend/util/name_generator.go new file mode 100644 index 0000000..c75adb0 --- /dev/null +++ b/backend/util/name_generator.go @@ -0,0 +1,28 @@ +package util + +import ( + "crypto/rand" + "math/big" + "strings" +) + +const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func GenerateName(prefix ...string) string { + n, _ := rand.Int(rand.Reader, big.NewInt(5)) + length := 6 + int(n.Int64()) + + result := make([]byte, length) + for i := range result { + idx, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) + result[i] = letters[idx.Int64()] + } + + var sb strings.Builder + for _, p := range prefix { + sb.WriteString(p) + } + sb.Write(result) + + return sb.String() +} diff --git a/backend/util/name_generator_test.go b/backend/util/name_generator_test.go new file mode 100644 index 0000000..ff0ac6a --- /dev/null +++ b/backend/util/name_generator_test.go @@ -0,0 +1,28 @@ +package util_test + +import ( + "github.com/stretchr/testify/assert" + "hyperion/backend/util" + "strings" + "testing" +) + +func TestGenerateName(t *testing.T) { + tests := []struct { + name string + want string + prefix []string + }{ + {"should return without prefix", "", []string{}}, + {"should return with prefix _v", "_v", []string{"_v"}}, + {"should return with prefix _c", "_c", []string{"_", "c"}}, + {"should return with prefix $", "$", []string{"$"}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := util.GenerateName(tt.prefix...) + + assert.True(t, strings.HasPrefix(got, tt.want)) + }) + } +} From d26e578c524da4fd56b4bc6be13a5759b265add2 Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Sat, 8 Mar 2025 13:45:21 +0800 Subject: [PATCH 5/7] github action for go --- .github/workflows/go-unit-test.yml | 25 +++++++++++++++++++++++++ backend/obfuscator/js/js_test.go | 9 ++------- 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/go-unit-test.yml diff --git a/.github/workflows/go-unit-test.yml b/.github/workflows/go-unit-test.yml new file mode 100644 index 0000000..8aa7935 --- /dev/null +++ b/.github/workflows/go-unit-test.yml @@ -0,0 +1,25 @@ +name: Go Unit Test + +on: + pull_request: + branches: + - develop + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23.4 + + - name: Install dependencies + run: go mod tidy + + - name: Run tests + run: go test -v -cover ./... \ No newline at end of file diff --git a/backend/obfuscator/js/js_test.go b/backend/obfuscator/js/js_test.go index e44d467..19ea03f 100644 --- a/backend/obfuscator/js/js_test.go +++ b/backend/obfuscator/js/js_test.go @@ -1,7 +1,6 @@ package js_test import ( - "fmt" "github.com/stretchr/testify/assert" "hyperion/backend/obfuscator/js" "os" @@ -39,19 +38,15 @@ func TestObfuscation_RemoveComment(t *testing.T) { } func TestObfuscation_RenameVariable(t *testing.T) { - content, err := obfuscator.RenameVariable(code) + _, err := obfuscator.RenameVariable(code) if err != nil { t.Fatal(err) } - - fmt.Println(content) } func TestObfuscation_RenameConstant(t *testing.T) { - content, err := obfuscator.RenameConstant(code) + _, err := obfuscator.RenameConstant(code) if err != nil { t.Fatal(err) } - - fmt.Println(content) } From f8ffe86f1c430b2375ff6be04d12ea2b2f4bee4b Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Sat, 8 Mar 2025 13:49:46 +0800 Subject: [PATCH 6/7] golang github action for FE --- .github/workflows/go-unit-test.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go-unit-test.yml b/.github/workflows/go-unit-test.yml index 8aa7935..1683ea7 100644 --- a/.github/workflows/go-unit-test.yml +++ b/.github/workflows/go-unit-test.yml @@ -18,8 +18,16 @@ jobs: with: go-version: 1.23.4 - - name: Install dependencies + - name: Install Go Dependencies run: go mod tidy + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.12.0 + + - name: Install JS Dependencies + run: npm install + - name: Run tests run: go test -v -cover ./... \ No newline at end of file From 735a812fdc9c9941618a08e256d4d0198d45c02e Mon Sep 17 00:00:00 2001 From: "M. Iqbal Effendi" Date: Sat, 8 Mar 2025 13:54:57 +0800 Subject: [PATCH 7/7] golang github action to build FE --- .github/workflows/go-unit-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go-unit-test.yml b/.github/workflows/go-unit-test.yml index 1683ea7..183e4ec 100644 --- a/.github/workflows/go-unit-test.yml +++ b/.github/workflows/go-unit-test.yml @@ -27,7 +27,10 @@ jobs: node-version: 20.12.0 - name: Install JS Dependencies - run: npm install + run: npm install --prefix frontend + + - name: Build Frontend to be embedded + run: npm run build --prefix frontend - name: Run tests run: go test -v -cover ./... \ No newline at end of file