From 3c6e217e192771442d09af6180b3bf3c0e0ae757 Mon Sep 17 00:00:00 2001 From: 6uf <84757238+suffz@users.noreply.github.com> Date: Mon, 5 Jun 2023 23:28:19 -0300 Subject: [PATCH] Add files via upload fit folders into a parent folder for organization. --- packages/Chrome/actions.go | 162 ++++ packages/Chrome/chrome_unix.go | 177 ++++ packages/Chrome/chrome_windows.go | 120 +++ packages/Chrome/config.go | 137 +++ packages/Chrome/display_unix.go | 165 ++++ packages/Chrome/scripts/test.sh | 263 ++++++ packages/Chrome/util/easyjson/easyjson.go | 38 + .../Chrome/util/easyjson/easyjson_test.go | 41 + packages/StrCmd/main.go | 286 +++++++ packages/StrCmd/types.go | 34 + packages/apiGO/mcsn.go | 468 ++++++++++ packages/apiGO/ping.go | 20 + packages/apiGO/proxy.go | 111 +++ packages/apiGO/send.go | 94 +++ packages/apiGO/var.go | 170 ++++ packages/h2/client.go | 115 +++ packages/h2/utils.go | 384 +++++++++ packages/h2/variables.go | 71 ++ packages/utils/auth.go | 799 ++++++++++++++++++ packages/utils/config.go | 101 +++ packages/utils/proxy.go | 31 + packages/utils/types.go | 166 ++++ packages/utils/utils.go | 62 ++ packages/webhook/main.go | 19 + packages/webhook/types.go | 44 + 25 files changed, 4078 insertions(+) create mode 100644 packages/Chrome/actions.go create mode 100644 packages/Chrome/chrome_unix.go create mode 100644 packages/Chrome/chrome_windows.go create mode 100644 packages/Chrome/config.go create mode 100644 packages/Chrome/display_unix.go create mode 100644 packages/Chrome/scripts/test.sh create mode 100644 packages/Chrome/util/easyjson/easyjson.go create mode 100644 packages/Chrome/util/easyjson/easyjson_test.go create mode 100644 packages/StrCmd/main.go create mode 100644 packages/StrCmd/types.go create mode 100644 packages/apiGO/mcsn.go create mode 100644 packages/apiGO/ping.go create mode 100644 packages/apiGO/proxy.go create mode 100644 packages/apiGO/send.go create mode 100644 packages/apiGO/var.go create mode 100644 packages/h2/client.go create mode 100644 packages/h2/utils.go create mode 100644 packages/h2/variables.go create mode 100644 packages/utils/auth.go create mode 100644 packages/utils/config.go create mode 100644 packages/utils/proxy.go create mode 100644 packages/utils/types.go create mode 100644 packages/utils/utils.go create mode 100644 packages/webhook/main.go create mode 100644 packages/webhook/types.go diff --git a/packages/Chrome/actions.go b/packages/Chrome/actions.go new file mode 100644 index 0000000..75fe56c --- /dev/null +++ b/packages/Chrome/actions.go @@ -0,0 +1,162 @@ +package chromedpundetected + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "time" + + "github.com/Davincible/chromedp-undetected/util/easyjson" + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/emulation" + "github.com/chromedp/cdproto/network" + "github.com/chromedp/chromedp" +) + +// Cookie is used to set browser cookies. +type Cookie struct { + Name string `json:"name" yaml:"name"` + Value string `json:"value" yaml:"value"` + Domain string `json:"domain" yaml:"domain"` + Path string `json:"path" yaml:"path"` + Expires float64 `json:"expires" yaml:"expires"` + HTTPOnly bool `json:"httpOnly" yaml:"httpOnly"` + Secure bool `json:"secure" yaml:"secure"` +} + +// UserAgentOverride overwrites the Chrome user agent. +// +// It's better to use this method than emulation.UserAgentOverride. +func UserAgentOverride(userAgent string) chromedp.ActionFunc { + return func(ctx context.Context) error { + return cdp.Execute(ctx, "Network.setUserAgentOverride", + emulation.SetUserAgentOverride(userAgent), nil) + } +} + +// LoadCookiesFromFile takes a file path to a json file containing cookies, and +// loads in the cookies into the browser. +func LoadCookiesFromFile(path string) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + f, err := os.Open(path) //nolint:gosec + if err != nil { + return fmt.Errorf("failed to open file '%s': %w", path, err) + } + + data, err := io.ReadAll(f) + if err != nil { + return err + } + + if err := f.Close(); err != nil { + return err + } + + var cookies []Cookie + if err := json.Unmarshal(data, &cookies); err != nil { + return fmt.Errorf("unmarshal cookies from json: %w", err) + } + + return LoadCookies(cookies)(ctx) + }) +} + +// LoadCookies will load a set of cookies into the browser. +func LoadCookies(cookies []Cookie) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + for _, cookie := range cookies { + expiry := cdp.TimeSinceEpoch(time.Unix(int64(cookie.Expires), 0)) + if err := network.SetCookie(cookie.Name, cookie.Value). + WithHTTPOnly(cookie.HTTPOnly). + WithSecure(cookie.Secure). + WithDomain(cookie.Domain). + WithPath(cookie.Path). + WithExpires(&expiry). + Do(ctx); err != nil { + return err + } + } + return nil + }) +} + +// SaveCookies extracts the cookies from the current URL and appends them to +// provided array. +func SaveCookies(cookies *[]Cookie) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + c, err := network.GetCookies().Do(ctx) + if err != nil { + return err + } + + for _, cookie := range c { + *cookies = append(*cookies, Cookie{ + Name: cookie.Name, + Value: cookie.Value, + Domain: cookie.Domain, + Path: cookie.Path, + Expires: cookie.Expires, + HTTPOnly: cookie.HTTPOnly, + Secure: cookie.HTTPOnly, + }) + } + + return nil + }) +} + +// SaveCookiesTo extracts the cookies from the current page and saves them +// as JSON to the provided path. +func SaveCookiesTo(path string) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + var c []Cookie + + if err := SaveCookies(&c).Do(ctx); err != nil { + return err + } + + b, err := json.Marshal(c) + if err != nil { + return err + } + + if err := os.WriteFile(path, b, 0644); err != nil { //nolint:gosec + return err + } + + return nil + }) +} + +// RunCommandWithRes runs any Chrome Dev Tools command, with any params and +// sets the result to the res parameter. Make sure it is a pointer. +// +// In contrast to the native method of chromedp, with this method you can directly +// pass in a map with the data passed to the command. +func RunCommandWithRes(method string, params, res any) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + i := easyjson.New(params) + o := easyjson.New(res) + + return cdp.Execute(ctx, method, i, o) + }) +} + +// RunCommand runs any Chrome Dev Tools command, with any params. +// +// In contrast to the native method of chromedp, with this method you can directly +// pass in a map with the data passed to the command. +func RunCommand(method string, params any) chromedp.ActionFunc { + return chromedp.ActionFunc(func(ctx context.Context) error { + i := easyjson.New(params) + + return cdp.Execute(ctx, method, i, nil) + }) +} + +// BlockURLs blocks a set of URLs in Chrome. +func BlockURLs(url ...string) chromedp.ActionFunc { + return RunCommand("Network.setBlockedURLs", map[string][]string{"urls": url}) +} diff --git a/packages/Chrome/chrome_unix.go b/packages/Chrome/chrome_unix.go new file mode 100644 index 0000000..70e19bc --- /dev/null +++ b/packages/Chrome/chrome_unix.go @@ -0,0 +1,177 @@ +//go:build unix + +// Package chromedpundetected provides a chromedp context with an undetected +// Chrome browser. +package chromedpundetected + +import ( + "context" + "net" + "os" + "os/exec" + "path" + "strconv" + "strings" + "syscall" + + "github.com/Xuanwo/go-locale" + "github.com/chromedp/chromedp" + "github.com/google/uuid" + "golang.org/x/exp/slog" +) + +var ( + // DefaultUserDirPrefix Defaults. + DefaultUserDirPrefix = "chromedp-undetected-" +) + +// New creates a context with an undetected Chrome executor. +func New(config Config) (context.Context, context.CancelFunc, error) { + var opts []chromedp.ExecAllocatorOption + + userDataDir := path.Join(os.TempDir(), DefaultUserDirPrefix+uuid.NewString()) + if len(config.ChromePath) > 0 { + userDataDir = config.ChromePath + } + + headlessOpts, closeFrameBuffer, err := headlessFlag(config) + if err != nil { + return nil, func() {}, err + } + + opts = append(opts, localeFlag()) + opts = append(opts, supressWelcomeFlag()...) + opts = append(opts, logLevelFlag(config)) + opts = append(opts, debuggerAddrFlag(config)...) + opts = append(opts, noSandboxFlag(config)...) + opts = append(opts, chromedp.UserDataDir(userDataDir)) + opts = append(opts, headlessOpts...) + opts = append(opts, config.ChromeFlags...) + + ctx := context.Background() + if config.Ctx != nil { + ctx = config.Ctx + } + + cancelT := func() {} + if config.Timeout > 0 { + ctx, cancelT = context.WithTimeout(ctx, config.Timeout) + } + + ctx, cancelA := chromedp.NewExecAllocator(ctx, opts...) + ctx, cancelC := chromedp.NewContext(ctx, config.ContextOptions...) + + cancel := func() { + cancelT() + cancelA() + cancelC() + + if err := closeFrameBuffer(); err != nil { + slog.Error("failed to close Xvfb", err) + } + + if len(config.ChromePath) == 0 { + _ = os.RemoveAll(userDataDir) //nolint:errcheck + } + } + + return ctx, cancel, nil +} + +func supressWelcomeFlag() []chromedp.ExecAllocatorOption { + return []chromedp.ExecAllocatorOption{ + chromedp.Flag("no-first-run", true), + chromedp.Flag("no-default-browser-check", true), + } +} + +func debuggerAddrFlag(config Config) []chromedp.ExecAllocatorOption { + port := strconv.Itoa(config.Port) + if config.Port == 0 { + port = getRandomPort() + } + + return []chromedp.ExecAllocatorOption{ + chromedp.Flag("remote-debugging-host", "127.0.0.1"), + chromedp.Flag("remote-debugging-port", port), + } +} + +func localeFlag() chromedp.ExecAllocatorOption { + lang := "en-US" + if tag, err := locale.Detect(); err != nil && len(tag.String()) > 0 { + lang = tag.String() + } + + return chromedp.Flag("lang", lang) +} + +func noSandboxFlag(config Config) []chromedp.ExecAllocatorOption { + var opts []chromedp.ExecAllocatorOption + + if config.NoSandbox { + opts = append(opts, + chromedp.Flag("no-sandbox", true), + chromedp.Flag("test-type", true)) + } + + return opts +} + +func logLevelFlag(config Config) chromedp.ExecAllocatorOption { + return chromedp.Flag("log-level", strconv.Itoa(config.LogLevel)) +} + +func headlessFlag(config Config) ([]chromedp.ExecAllocatorOption, func() error, error) { + var opts []chromedp.ExecAllocatorOption + + cleanup := func() error { return nil } + + if config.Headless { + // Create virtual display + frameBuffer, err := newFrameBuffer("1920x1080x24") + if err != nil { + return nil, nil, err + } + + cleanup = frameBuffer.Stop + + opts = append(opts, + // chromedp.Flag("headless", true), + chromedp.Flag("window-size", "1920,1080"), + chromedp.Flag("start-maximized", true), + chromedp.Flag("no-sandbox", true), + chromedp.ModifyCmdFunc(func(cmd *exec.Cmd) { + cmd.Env = append(cmd.Env, "DISPLAY=:"+frameBuffer.Display) + cmd.Env = append(cmd.Env, "XAUTHORITY="+frameBuffer.AuthPath) + + // Default modify command per chromedp + if _, ok := os.LookupEnv("LAMBDA_TASK_ROOT"); ok { + // do nothing on AWS Lambda + return + } + + if cmd.SysProcAttr == nil { + cmd.SysProcAttr = new(syscall.SysProcAttr) + } + + // When the parent process dies (Go), kill the child as well. + cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL + }), + ) + } + + return opts, cleanup, nil +} + +func getRandomPort() string { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err == nil { + addr := l.Addr().String() + _ = l.Close() //nolint:errcheck,gosec + + return strings.Split(addr, ":")[1] + } + + return "42069" +} diff --git a/packages/Chrome/chrome_windows.go b/packages/Chrome/chrome_windows.go new file mode 100644 index 0000000..f660dd1 --- /dev/null +++ b/packages/Chrome/chrome_windows.go @@ -0,0 +1,120 @@ +// Package chromedpundetected provides a chromedp context with an undetected +// Chrome browser. +package chromedpundetected + +import ( + "context" + "net" + "os" + "path" + "strconv" + "strings" + + "github.com/Xuanwo/go-locale" + "github.com/chromedp/chromedp" + "github.com/google/uuid" +) + +var ( + // DefaultUserDirPrefix Defaults. + DefaultUserDirPrefix = "chromedp-undetected-" +) + +// New creates a context with an undetected Chrome executor. +func New(config Config) (context.Context, context.CancelFunc, error) { + var opts []chromedp.ExecAllocatorOption + + userDataDir := path.Join(os.TempDir(), DefaultUserDirPrefix+uuid.NewString()) + if len(config.ChromePath) > 0 { + userDataDir = config.ChromePath + } + + opts = append(opts, localeFlag()) + opts = append(opts, supressWelcomeFlag()...) + opts = append(opts, logLevelFlag(config)) + opts = append(opts, debuggerAddrFlag(config)...) + opts = append(opts, noSandboxFlag(config)...) + opts = append(opts, chromedp.UserDataDir(userDataDir)) + opts = append(opts, config.ChromeFlags...) + + ctx := context.Background() + if config.Ctx != nil { + ctx = config.Ctx + } + + cancelT := func() {} + if config.Timeout > 0 { + ctx, cancelT = context.WithTimeout(ctx, config.Timeout) + } + + ctx, cancelA := chromedp.NewExecAllocator(ctx, opts...) + ctx, cancelC := chromedp.NewContext(ctx, config.ContextOptions...) + + cancel := func() { + cancelT() + cancelA() + cancelC() + + if len(config.ChromePath) == 0 { + _ = os.RemoveAll(userDataDir) //nolint:errcheck + } + } + + return ctx, cancel, nil +} + +func supressWelcomeFlag() []chromedp.ExecAllocatorOption { + return []chromedp.ExecAllocatorOption{ + chromedp.Flag("no-first-run", true), + chromedp.Flag("no-default-browser-check", true), + } +} + +func debuggerAddrFlag(config Config) []chromedp.ExecAllocatorOption { + port := strconv.Itoa(config.Port) + if config.Port == 0 { + port = getRandomPort() + } + + return []chromedp.ExecAllocatorOption{ + chromedp.Flag("remote-debugging-host", "127.0.0.1"), + chromedp.Flag("remote-debugging-port", port), + } +} + +func localeFlag() chromedp.ExecAllocatorOption { + lang := "en-US" + if tag, err := locale.Detect(); err != nil && len(tag.String()) > 0 { + lang = tag.String() + } + + return chromedp.Flag("lang", lang) +} + +func noSandboxFlag(config Config) []chromedp.ExecAllocatorOption { + var opts []chromedp.ExecAllocatorOption + + if config.NoSandbox { + opts = append(opts, + chromedp.Flag("no-sandbox", true), + chromedp.Flag("test-type", true)) + } + + return opts +} + +func logLevelFlag(config Config) chromedp.ExecAllocatorOption { + return chromedp.Flag("log-level", strconv.Itoa(config.LogLevel)) +} + +func getRandomPort() string { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err == nil { + addr := l.Addr().String() + _ = l.Close() //nolint:errcheck,gosec + + return strings.Split(addr, ":")[1] + } + + return "42069" +} diff --git a/packages/Chrome/config.go b/packages/Chrome/config.go new file mode 100644 index 0000000..dd55f13 --- /dev/null +++ b/packages/Chrome/config.go @@ -0,0 +1,137 @@ +package chromedpundetected + +import ( + "context" + "time" + + "github.com/chromedp/chromedp" +) + +const ( + // DefaultNoSandbox enables the 'no-sandbox' flag by default. + DefaultNoSandbox = true +) + +// Option is a functional option. +type Option func(*Config) + +// Config is a undetected Chrome config. +type Config struct { + // Ctx is the base context to use. By default, a background context will be used. + Ctx context.Context `json:"-" yaml:"-"` + + // ContextOptions are chromedp context option. + ContextOptions []chromedp.ContextOption `json:"-" yaml:"-"` + + // ChromeFlags are additional Chrome flags to pass to the browser. + // + // NOTE: adding additional flags can make the detection unstable, so test, + // and be careful of what flags you add. Mostly intended to configure things + // like a proxy. Also check if the flags you want to set are not already set + // by this library. + ChromeFlags []chromedp.ExecAllocatorOption + + // UserDataDir is the path to the directory where Chrome user data is stored. + // + // By default a temporary directory will be used. + UserDataDir string `json:"userDataDir" yaml:"userDataDir"` + + // LogLevel is the Chrome log level, 0 by default. + LogLevel int `json:"logLevel" yaml:"logLevel"` + + // NoSandbox dictates whether the no-sanbox flag is added. Defaults to true. + NoSandbox bool `json:"noSandbox" yaml:"noSandbox"` + + // ChromePath is a specific binary path for Chrome. + // + // By default the chrome or chromium on your PATH will be used. + ChromePath string `json:"chromePath" yaml:"chromePath"` + + // Port is the Chrome debugger port. By default a random port will be used. + Port int `json:"port" yaml:"port"` + + // Timeout is the context timeout. + Timeout time.Duration `json:"timeout" yaml:"timeout"` + + // Headless dicates whether Chrome will start headless (without a visible window) + // + // It will NOT use the '--headless' option, rather it will use a virtual display. + // Requires Xvfb to be installed, only available on Linux. + Headless bool `json:"headless" yaml:"headless"` +} + +// NewConfig creates a new config object with defaults. +func NewConfig(opts ...Option) Config { + c := Config{ + NoSandbox: DefaultNoSandbox, + } + + for _, o := range opts { + o(&c) + } + + return c +} + +// WithContext adds a base context. +func WithContext(ctx context.Context) Option { + return func(c *Config) { + c.Ctx = ctx + } +} + +// WithUserDataDir sets the user data directory to a custom path. +func WithUserDataDir(dir string) Option { + return func(c *Config) { + c.UserDataDir = dir + } +} + +// WithChromeBinary sets the chrome binary path. +func WithChromeBinary(path string) Option { + return func(c *Config) { + c.ChromePath = path + } +} + +// WithTimeout sets the context timeout. +func WithTimeout(timeout time.Duration) Option { + return func(c *Config) { + c.Timeout = timeout + } +} + +// WithHeadless creates a headless chrome instance. +func WithHeadless() Option { + return func(c *Config) { + c.Headless = true + } +} + +// WithNoSandbox enable/disable sandbox. Disabled by default. +func WithNoSandbox(b bool) Option { + return func(c *Config) { + c.NoSandbox = b + } +} + +// WithPort sets the chrome debugger port. +func WithPort(port int) Option { + return func(c *Config) { + c.Port = port + } +} + +// WithLogLevel sets the chrome log level. +func WithLogLevel(level int) Option { + return func(c *Config) { + c.LogLevel = level + } +} + +// WithChromeFlags add chrome flags. +func WithChromeFlags(opts ...chromedp.ExecAllocatorOption) Option { + return func(c *Config) { + c.ChromeFlags = append(c.ChromeFlags, opts...) + } +} diff --git a/packages/Chrome/display_unix.go b/packages/Chrome/display_unix.go new file mode 100644 index 0000000..6509f6d --- /dev/null +++ b/packages/Chrome/display_unix.go @@ -0,0 +1,165 @@ +//go:build unix + +package chromedpundetected + +import ( + "bufio" + "errors" + "fmt" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "syscall" + "time" + + "golang.org/x/exp/slog" +) + +// Errors. +var ( + ErrXvfbNotFound = errors.New("xvfb not found. Please install (Linux only)") +) + +// frameBuffer controls an X virtual frame buffer running as a background +// process. +type frameBuffer struct { + // Display is the X11 display number that the Xvfb process is hosting + // (without the preceding colon). + Display string + + // AuthPath is the path to the X11 authorization file that permits X clients + // to use the X server. This is typically provided to the client via the + // XAUTHORITY environment variable. + AuthPath string + + cmd *exec.Cmd +} + +// newFrameBuffer starts an X virtual frame buffer running in the background. +// FrameBufferOptions may be populated to change the behavior of the frame buffer. +func newFrameBuffer(screenSize string) (*frameBuffer, error) { //nolint:funlen + if err := exec.Command("which", "Xvfb").Run(); err != nil { + return nil, ErrXvfbNotFound + } + + pipeReader, pipeWriter, err := os.Pipe() + if err != nil { + return nil, err + } + + defer func() { + if err = pipeReader.Close(); err != nil { + slog.Error("failed to close pipe reader", err) + } + }() + + authPath, err := tempFile("chromedp-xvfb") + if err != nil { + return nil, err + } + + // Xvfb will print the display on which it is listening to file descriptor 3, + // for which we provide a pipe. + arguments := []string{"-displayfd", "3", "-nolisten", "tcp"} + + if screenSize != "" { + screenSizeExpression := regexp.MustCompile(`^\d+x\d+(?:x\d+)$`) + if !screenSizeExpression.MatchString(screenSize) { + return nil, fmt.Errorf("invalid screen size: expected 'WxH[xD]', got %q", screenSize) + } + + arguments = append(arguments, "-screen", "0", screenSize) + } + + xvfb := exec.Command("Xvfb", arguments...) + xvfb.ExtraFiles = []*os.File{pipeWriter} + xvfb.Env = append(xvfb.Env, "XAUTHORITY="+authPath) + + if xvfb.SysProcAttr == nil { + xvfb.SysProcAttr = new(syscall.SysProcAttr) + } + + xvfb.SysProcAttr.Pdeathsig = syscall.SIGKILL + + if err := xvfb.Start(); err != nil { + return nil, err + } + + if err := pipeWriter.Close(); err != nil { + return nil, err + } + + type resp struct { + display string + err error + } + + ch := make(chan resp) + + go func() { + bufr := bufio.NewReader(pipeReader) + s, err := bufr.ReadString('\n') + ch <- resp{s, err} + }() + + var display string + select { + case resp := <-ch: + if resp.err != nil { + return nil, resp.err + } + + display = strings.TrimSpace(resp.display) + if _, err := strconv.Atoi(display); err != nil { + return nil, errors.New("xvfb did not print the display number") + } + + case <-time.After(10 * time.Second): + return nil, errors.New("timeout waiting for Xvfb") + } + + xauth := exec.Command("xauth", "generate", ":"+display, ".", "trusted") //nolint:gosec + xauth.Env = append(xauth.Env, "XAUTHORITY="+authPath) + // Make this conditional? + xauth.Stderr = os.Stderr + xauth.Stdout = os.Stdout + + if err := xauth.Run(); err != nil { + return nil, err + } + + return &frameBuffer{display, authPath, xvfb}, nil +} + +// Stop kills the background frame buffer process and removes the X +// authorization file. +func (f frameBuffer) Stop() error { + if err := f.cmd.Process.Kill(); err != nil { + return err + } + + _ = os.Remove(f.AuthPath) //nolint:errcheck + + if err := f.cmd.Wait(); err != nil && err.Error() != "signal: killed" { + return err + } + + return nil +} + +func tempFile(pattern string) (string, error) { + tempFile, err := os.CreateTemp("", pattern) + if err != nil { + return "", err + } + + fileName := tempFile.Name() + + if err := tempFile.Close(); err != nil { + return "", err + } + + return fileName, nil +} diff --git a/packages/Chrome/scripts/test.sh b/packages/Chrome/scripts/test.sh new file mode 100644 index 0000000..44bb364 --- /dev/null +++ b/packages/Chrome/scripts/test.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +GO_TEST_FLAGS="-v -race -cover -bench=." + +RED='\033[0;31m' +NC='\033[0m' +GREEN='\033[0;32m' +BAR="-------------------------------------------------------------------------------" +HAS_DEPS=() + +export RICHGO_FORCE_COLOR="true" + +# Print a green colored message to the screen. +function print_msg() { + printf "\n\n${GREEN}${BAR}${NC}\n" + printf "${GREEN}| > ${1}${NC}\n" + printf "${GREEN}${BAR}${NC}\n\n" + sleep 1 +} + +# Print a red colored message to the screen. +function print_red() { + printf "\n\n${RED}${BAR}${NC}\n" + printf "${RED}| > ${1}${NC}\n" + printf "${RED}${BAR}${NC}\n\n" + sleep 1 +} + +# Print the contents of the directory array. +function print_list() { + dirs=$1 + + print_msg "Found ${#dirs[@]} directories to test" + echo "Changed dirs:" + printf '%s \n' "${dirs[@]}" + printf '\n\n' + sleep 1 +} + +# Add a job summary to GitHub Actions. +function add_summary() { + printf "${1}\n" >>$GITHUB_STEP_SUMMARY +} + +# Install dependencies, usually servers. +# +# Can can be used to run an script needed to complete tests. +# +# To run a script add it to the HAS_DEPS variable, e.g.: ("redis" "nats"). +# And make sure to add a script to deps/.sh +function install_deps() { + for dep in "${HAS_DEPS[@]}"; do + if grep -q "${dep}" <<<"${1}"; then + script="scripts/deps/${dep}.sh" + + # Check if script exists + if [[ -f ${script} ]]; then + echo "Installing depencies for $dep" + bash "${script}" + echo "$dep" + return 0 + fi + fi + done +} + +# Kill all PIDs of setups. +function kill_deps() { + for dep in "${HAS_DEPS[@]}"; do + if grep -q "${dep}" <<<"${1}"; then + # Itterate over all PIDs and kill them. + pids=($(pgrep "$dep")) + if [[ ${#pids[@]} -ne 0 ]]; then + echo "Killing:" + fi + + for dep_pid in "${pids[@]}"; do + ps -aux | grep -v "grep" | grep "${dep_pid}" + + kill "${dep_pid}" + return 0 + done + fi + done +} + +# Find directories that contain changes. +function find_changes() { + # Find all directories that have changed files. + changes=($(git diff --name-only origin/main | xargs -d'\n' -I{} dirname {} | sort -u)) + + # Filter out directories without go.mod files. + changes=($(find "${changes[@]}" -maxdepth 1 -name 'go.mod' -printf '%h\n')) + + echo "${changes[@]}" +} + +# Find all go directories. +function find_all() { + find . -name 'go.mod' -printf '%h\n' +} + +# Get the dir list based on command type. +function get_dirs() { + if [[ $1 == "all" ]]; then + find_all + else + find_changes + fi +} + +# Run GoLangCi Linters. +function run_linter() { + curl -sSfL "https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh" | sh -s -- -b $(go env GOPATH)/bin + + echo + golangci-lint --version + + cwd=$(pwd) + dirs=$1 + failed="false" + for dir in "${dirs[@]}"; do + pushd "${dir}" >/dev/null + print_msg "Running linter on ${dir}" + + golangci-lint run --out-format github-actions -c "${cwd}/.golangci.yaml" + + # Keep track of exit code of linter + if [[ $? -ne 0 ]]; then + failed="true" + fi + + popd >/dev/null + done + + if [[ $failed == "true" ]]; then + add_summary "## Autofix Linting Issues" + add_summary "The linter can sometimes autofix some of the issues, if it is supported." + add_summary "\`\`\`bash\ncd \ngolangci-lint run -c /.golangci.yaml --fix\n\`\`\`" + print_red "Linter failed" + exit 1 + else + print_msg "Linter found no issues" + fi +} + +# Run Unit tests with RichGo for pretty output. +function run_test() { + cwd=$(pwd) + dirs=$1 + failed="false" + + print_msg "Downloading dependencies..." + + go install github.com/kyoh86/richgo@latest + + for dir in "${dirs[@]}"; do + bash -c "cd ${dir}; go mod tidy &>/dev/null" + done + + for dir in "${dirs[@]}"; do + print_msg "Running unit tests for $dir" + + # Install dependencies if required. + install_deps "${dir}" + + pushd "${dir}" >/dev/null + + # Download all modules. + go get -v -t -d ./... + + # Run tests. + richgo test $GO_TEST_FLAGS ./... + + # Keep track of exit code. + if [[ $? -ne 0 ]]; then + failed="true" + fi + + popd >/dev/null + + # Kill all depdency processes. + kill_deps "${dir}" + done + + if [[ $failed == "true" ]]; then + print_red "Tests failed" + exit 1 + fi +} + +# Run unit tests with tparse to create a summary. +function create_summary() { + go install github.com/mfridman/tparse@latest + + add_summary "## Test Summary" + + cwd=$(pwd) + dirs=$1 + failed="false" + for dir in "${dirs[@]}"; do + # Install dependencies if required. + install_deps "${dir}" + + pushd "${dir}" >/dev/null + print_msg "Creating summary for $dir" + + add_summary "\n### ${dir}\n" + + # Download all modules. + go get -v -t -d ./... + + go test $GO_TEST_FLAGS -json ./... | + tparse -notests -format=markdown >>$GITHUB_STEP_SUMMARY + + if [[ $? -ne 0 ]]; then + failed="true" + fi + + popd >/dev/null + + # Kill all depdency processes. + kill_deps "${dir}" + done + + if [[ $failed == "true" ]]; then + print_red "Tests failed" + exit 1 + fi +} + +case $1 in +"lint") + dirs=($(get_dirs "${2}")) + [[ ${#dirs[@]} -eq 0 ]] && print_red "No changed Go files detected" && exit 0 + + print_list "${dirs[@]}" + run_linter "${dirs[@]}" + ;; +"test") + dirs=($(get_dirs "${2}")) + [[ ${#dirs[@]} -eq 0 ]] && print_red "No changed Go files detected" && exit 0 + + print_list "${dirs[@]}" + + run_test "${dirs[@]}" + ;; +"summary") + dirs=($(get_dirs "${2}")) + [[ ${#dirs[@]} -eq 0 ]] && print_red "No changed Go files detected" && exit 0 + + print_list "${dirs[@]}" + create_summary "${dirs[@]}" + ;; +"") + printf "Please provide a command [lint, test, summary]." + exit 1 + ;; +*) + printf "Command not found: $1. Select one of [lint, test, summary]" + exit 1 + ;; +esac diff --git a/packages/Chrome/util/easyjson/easyjson.go b/packages/Chrome/util/easyjson/easyjson.go new file mode 100644 index 0000000..cacaa48 --- /dev/null +++ b/packages/Chrome/util/easyjson/easyjson.go @@ -0,0 +1,38 @@ +// Package easyjson provides utilities for use with easyjson. +package easyjson + +import ( + "encoding/json" + + "github.com/mailru/easyjson" + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" +) + +var _ easyjson.MarshalerUnmarshaler = (*GenericEJ[any])(nil) + +// New creates a new geneic EasyJSON container. +func New[T any](data T) *GenericEJ[T] { + return &GenericEJ[T]{data} +} + +// GenericEJ is a type that uses the stdlib json (un)marshaler to make any +// type compatible with easyjson by implementing the EasyJSON interfaces. +type GenericEJ[T any] struct { + Data T +} + +// MarshalEasyJSON marshals any type to json with use of the stdlib json pkg. +func (t *GenericEJ[T]) MarshalEasyJSON(w *jwriter.Writer) { + b, err := json.Marshal(t.Data) + + w.Buffer.AppendBytes(b) + w.Error = err +} + +// UnmarshalEasyJSON unmarshals any type from json with use of the stdlib json pkg. +func (t *GenericEJ[T]) UnmarshalEasyJSON(w *jlexer.Lexer) { + if err := json.Unmarshal(w.Data, &t.Data); err != nil { + w.AddError(err) + } +} diff --git a/packages/Chrome/util/easyjson/easyjson_test.go b/packages/Chrome/util/easyjson/easyjson_test.go new file mode 100644 index 0000000..f2e8150 --- /dev/null +++ b/packages/Chrome/util/easyjson/easyjson_test.go @@ -0,0 +1,41 @@ +package easyjson + +import ( + "testing" + + "github.com/mailru/easyjson" + "github.com/stretchr/testify/require" +) + +func TestEasyJSONMap(t *testing.T) { + a := map[string]any{ + "one": 1.8, + "two": "two", + } + + b := New(a) + + j, err := easyjson.Marshal(b) + require.NoError(t, err, "marshal") + t.Log(string(j)) + + n := New(map[string]any{}) + + require.NoError(t, easyjson.Unmarshal(j, n)) + require.Equal(t, a, n.Data) +} + +func TestEasyJSONSlice(t *testing.T) { + a := []string{"a", "b", "c", "d"} + + b := New(a) + + j, err := easyjson.Marshal(b) + require.NoError(t, err, "marshal") + t.Log(string(j)) + + n := New([]string{}) + + require.NoError(t, easyjson.Unmarshal(j, n)) + require.Equal(t, a, n.Data) +} diff --git a/packages/StrCmd/main.go b/packages/StrCmd/main.go new file mode 100644 index 0000000..3612e6e --- /dev/null +++ b/packages/StrCmd/main.go @@ -0,0 +1,286 @@ +package StrCmd + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +var Current CommandArgs + +func (Data *App) ParseCommand(Text string) error { + var Args CommandArgs + var Default Command + var Names string + var ParsedNames []string = strings.Split(Text, " ") + var GennedArg = []GennedArgs{} + + for _, names := range ParsedNames { + if d, ok := Data.Commands[names]; ok { + Default = d + Names = names + } + } + if len(Default.Args) > 0 { + var l int + for _, a := range Default.Args { + if strings.Contains(Text, a) { + l++ + } + } + for i, Args := range Default.Args { + if strings.Contains(Text, Args) { + if strings.Contains(Args, "--") { + GennedArg = append(GennedArg, GennedArgs{ + Name: Args, + Value: "true", + IsBool: strings.Contains(Args, "--"), + }) + } else { + var Name string + if l <= len(Default.Args) && i+1 != len(Default.Args) && i+1 <= l { + Name = strings.TrimSpace(strings.Split(strings.Split(Text, Args)[1], Default.Args[i+1])[0]) + } else { + Name = strings.TrimSpace(strings.Split(Text, Args)[1]) + } + for _, d := range Default.Args { + if strings.Contains(Name, d) { + Name = strings.TrimRight(strings.ReplaceAll(Name, d, ""), " ") + } + } + GennedArg = append(GennedArg, GennedArgs{ + Name: Args, + Value: Name, + IsBool: strings.Contains(Name, "--"), + }) + } + } + } + Args = CommandArgs{ + Name: Names, + Args: GennedArg, + } + } + + var UsingSub bool + + if Default.Subcommand != nil { + var UptoDate SubCmd + for _, names := range ParsedNames { + if d, ok := Default.Subcommand[names]; ok { + UptoDate = d + UsingSub = true + Names = names + break + } + } + if UsingSub { + if len(UptoDate.Args) > 0 { + var l int + for _, a := range UptoDate.Args { + if strings.Contains(Text, a) { + l++ + } + } + for i, Args := range UptoDate.Args { + if strings.Contains(Text, Args) { + if strings.Contains(Args, "--") { + GennedArg = append(GennedArg, GennedArgs{ + Name: Args, + Value: "true", + IsBool: strings.Contains(Args, "--"), + }) + } else { + var Name string + if l <= len(UptoDate.Args) && i+1 != len(UptoDate.Args) && i+1 <= l { + Name = strings.TrimSpace(strings.Split(strings.Split(Text, Args)[1], UptoDate.Args[i+1])[0]) + } else { + Name = strings.TrimSpace(strings.Split(Text, Args)[1]) + } + for _, d := range UptoDate.Args { + if strings.Contains(Name, d) { + Name = strings.TrimRight(strings.ReplaceAll(Name, d, ""), " ") + } + } + GennedArg = append(GennedArg, GennedArgs{ + Name: Args, + Value: Name, + IsBool: strings.Contains(Name, "--"), + }) + } + } + } + Args = CommandArgs{ + Name: Names, + Args: GennedArg, + } + } + } + + Current = Args + if UptoDate.Action != nil { + UptoDate.Action() + } + } + + if !UsingSub { + if !Data.DontUseBuiltinHelpCmd { + if strings.HasPrefix(Text, "help") { + fmt.Println(Data.FormatHelpText()) + } + } + Current = Args + if Default.Action != nil { + Default.Action() + } + } + + return nil +} + +func (Data *App) FormatHelpText() (Base string) { + if Data.Version != "" { + Base += fmt.Sprintf("VERSION: %v\n\n", Data.Version) + } else { + Base += "VERSION: 1.0.0\n\n" + } + if Data.AppDescription != "" { + Base += "Description: " + Data.AppDescription + "\n\n" + } + Base += ReturnCommandInfo(Data.Commands, " [ARGS") + return +} + +func ReturnCommandInfo(Value map[string]Command, Format string) (Base string) { + for name, key := range Value { + if key.Description == "" { + key.Description = "A global command that is parsed through StrCmd (Description was empty!)" + } + + var B string = Format + D := " SUBCMD(S)\n" + var S string = D + if len(key.Args) > 0 { + for _, name := range key.Args { + B += " " + name + } + B += "]" + } + + for name, key := range key.Subcommand { + if key.Description == "" { + key.Description = "A global command that is parsed through StrCmd (Description was empty!)" + } + + var B string = Format + if len(key.Args) > 0 { + for _, name := range key.Args { + B += " " + name + } + B += "]" + } + + if B != Format { + S += fmt.Sprintf(" + %v | %v%v\n", name, key.Description, B) + } else { + S += fmt.Sprintf(" + %v | %v\n", name, key.Description) + } + } + + switch { + case B != Format && S != D: + Base += fmt.Sprintf("- %v | %v%v\n%v", name, key.Description, B, S) + case S != D: + Base += fmt.Sprintf("- %v | %v\n%v", name, key.Description, S) + case B != Format: + Base += fmt.Sprintf("- %v | %v%v\n", name, key.Description, B) + default: + Base += fmt.Sprintf("- %v | %v\n", name, key.Description) + } + } + return +} + +func (D *App) Run() error { + for { + if err := D.ParseCommand(Listen(true, D.Display)); err != nil { + return err + } + } +} + +func (D *App) Input(inputin string) error { + if err := D.ParseCommand(inputin); err != nil { + return err + } + return nil +} + +func Listen(show bool, input string) string { + fmt.Print(input) + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + return scanner.Text() +} + +func String(Arg string) string { + for _, arg := range Current.Args { + if arg.Name == Arg { + return arg.Value + } + } + return "" +} + +func Int(Arg string) int { + for _, arg := range Current.Args { + if arg.Name == Arg { + if value, err := strconv.Atoi(arg.Value); err == nil { + return value + } + } + } + return 0 +} + +func Bool(Arg string) bool { + for _, arg := range Current.Args { + if arg.Name == Arg && arg.IsBool { + return true + } + } + return false +} + +func Interface(Arg string) interface{} { + for _, arg := range Current.Args { + if arg.Name == Arg { + return arg.Value + } + } + return nil +} + +func Float64(Arg string) float64 { + for _, arg := range Current.Args { + if arg.Name == Arg { + if s, err := strconv.ParseFloat(arg.Value, 64); err == nil { + return s + } + } + } + return 0 +} + +func Float32(Arg string) float64 { + for _, arg := range Current.Args { + if arg.Name == Arg { + if s, err := strconv.ParseFloat(arg.Value, 32); err == nil { + return s + } + } + } + return 0 +} diff --git a/packages/StrCmd/types.go b/packages/StrCmd/types.go new file mode 100644 index 0000000..6418508 --- /dev/null +++ b/packages/StrCmd/types.go @@ -0,0 +1,34 @@ +package StrCmd + +type App struct { + Display string + Commands map[string]Command + Version string + AppDescription string + DontUseBuiltinHelpCmd bool + Args []CommandArgs +} + +type Command struct { + Description string + Subcommand map[string]SubCmd + Args []string + Action func() +} + +type SubCmd struct { + Description string + Args []string + Action func() +} + +type CommandArgs struct { + Name string + Args []GennedArgs +} + +type GennedArgs struct { + Name string + Value string + IsBool bool +} diff --git a/packages/apiGO/mcsn.go b/packages/apiGO/mcsn.go new file mode 100644 index 0000000..2904df1 --- /dev/null +++ b/packages/apiGO/mcsn.go @@ -0,0 +1,468 @@ +package apiGO + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/cookiejar" + "net/url" + "os" + "os/exec" + "reflect" + "regexp" + "runtime" + "strconv" + "strings" + "time" + + "main/packages/h2" + + tls2 "github.com/bogdanfinn/utls" +) + +func (accountBearer MCbearers) CreatePayloads(name string) (Data Payload) { + for _, bearer := range accountBearer.Details { + if bearer.AccountType == "Giftcard" { + Data.Payload = append(Data.Payload, fmt.Sprintf("POST /minecraft/profile HTTP/1.1\r\nHost: api.minecraftservices.com\r\nConnection: open\r\nContent-Length:%s\r\nContent-Type: application/json\r\nAccept: application/json\r\nAuthorization: Bearer %s\r\n\r\n"+string([]byte(`{"profileName":"`+name+`"}`))+"\r\n", strconv.Itoa(len(string([]byte(`{"profileName":"`+name+`"}`)))), bearer.Bearer)) + } else { + Data.Payload = append(Data.Payload, "PUT /minecraft/profile/name/"+name+" HTTP/1.1\r\nHost: api.minecraftservices.com\r\nUser-Agent: MCSN/1.0\r\nContent-Length:0\r\nAuthorization: bearer "+bearer.Bearer+"\r\n\r\n") + } + } + + return +} + +func Sleep(dropTime int64, delay float64) { + time.Sleep(time.Until(time.Unix(dropTime, 0).Add(time.Millisecond * time.Duration(0-delay)).Add(time.Duration(-float64(time.Since(time.Now()).Nanoseconds())/1000000.0) * time.Millisecond))) +} + +func BuxDroptimes(name string) (int64, int64) { + var data NameRequest + resp, _ := http.Get("https://buxflip.com/data/info/" + name) + b, _ := io.ReadAll(resp.Body) + json.Unmarshal(b, &data) + if !reflect.DeepEqual(data, NameRequest{}) { + return data.Start, data.End + } + return 0, 0 +} + +func StarShoppingDroptime(name string) (int64, int64) { + resp, _ := http.NewRequest("GET", + "http://api.star.shopping/droptime/"+name, + nil) + resp.Header.Set("user-agent", "Sniper") + + data, _ := http.DefaultClient.Do(resp) + dropTimeBytes, _ := io.ReadAll(data.Body) + var f Payload + json.Unmarshal(dropTimeBytes, &f) + return f.Start, f.End +} + +func DropTime(name string) (int64, int64) { + if Start, End := BuxDroptimes(name); Start > 0 && End > 0 { + return Start, End + } + if Start, End := StarShoppingDroptime(name); Start > 0 && End > 0 { + return Start, End + } + return 0, 0 +} + +func GetConfig(owo []byte) (Config map[string]interface{}) { + json.Unmarshal(owo, &Config) + return +} + +func Sum(array []float64) (sum float64) { + for _, ammount := range array { + sum = sum + ammount + } + + return +} + +func CheckChange(bearer string, PS *h2.ProxyAuth) bool { + var Conn h2.Conn + var err error + if PS != nil { + Conn, err = (&h2.Client{Config: h2.GetDefaultConfig()}).Connect("https://api.minecraftservices.com/minecraft/profile/namechange", h2.ReqConfig{ID: 1, BuildID: tls2.HelloChrome_112, DataBodyMaxLength: 1609382, Proxy: PS}) + } else { + Conn, err = (&h2.Client{Config: h2.GetDefaultConfig()}).Connect("https://api.minecraftservices.com/minecraft/profile/namechange", h2.ReqConfig{ID: 1, BuildID: tls2.HelloChrome_112, DataBodyMaxLength: 1609382}) + } + if err != nil { + return false + } else { + Conn.AddHeader("Authorization", "Bearer "+bearer) + if resp, err := Conn.Do("GET", "", "", nil); err == nil { + switch resp.Status { + case "200": + var Data struct { + NC bool `json:"nameChangeAllowed"` + } + json.Unmarshal(resp.Data, &Data) + return Data.NC + case "404": + return true + default: + return false + } + } else { + return false + } + } +} + +func SocketSending(conn *tls.Conn, payload string) Resp { + fmt.Fprintln(conn, payload) + sendTime := time.Now() + recvd := make([]byte, 4069) + conn.Read(recvd) + return Resp{ + RecvAt: time.Now(), + StatusCode: string(recvd[9:12]), + SentAt: sendTime, + Body: string(recvd), + } +} + +func (server ServerInfo) SendWebhook(body []byte) (Req *http.Response, err error) { + Req, err = http.Post(server.Webhook, "application/json", bytes.NewReader(body)) + if err != nil { + return nil, err + } + + return +} + +func ChangeSkin(body []byte, bearer string) (Req *http.Response, err error) { + resp, err := http.NewRequest("POST", "https://api.minecraftservices.com/minecraft/profile/skins", bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + + resp.Header.Set("Authorization", "bearer "+bearer) + + Req, err = http.DefaultClient.Do(resp) + if err != nil { + return nil, err + } + + return +} + +var ( + UrlPost = regexp.MustCompile(`urlPost:'(.+?)'`) + Value = regexp.MustCompile(`value="(.*?)"`) + User_Authenticate = `{"Properties": {"AuthMethod": "RPS", "SiteName": "user.auth.xboxlive.com", "RpsTicket": "%v"}, "RelyingParty": "http://auth.xboxlive.com", "TokenType": "JWT"}` + Xsts_Authenticate = `{"Properties": {"SandboxId": "RETAIL", "UserTokens": ["%v"]}, "RelyingParty": "rp://api.minecraftservices.com/", "TokenType": "JWT"}` + Login_With_Xbox = `{"identityToken" : "XBL3.0 x=%v;%v", "ensureLegacyEnabled" : true}` +) + +type ProxyMS struct { + IP string + Port string + User string + Password string +} + +func MS_authentication(e, p string, PS *ProxyMS) (returnDetails Info) { + redirect, bearerMS := "", mojangData{} + if jar, err := cookiejar.New(nil); err == nil { + Client := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error { redirect = req.URL.String(); return nil }, Transport: &http.Transport{TLSClientConfig: &tls.Config{Renegotiation: tls.RenegotiateFreelyAsClient}}, Jar: jar} + if resp, err := Client.Get("https://login.live.com/oauth20_authorize.srf?client_id=000000004C12AE6F&redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=service::user.auth.xboxlive.com::MBI_SSL&display=touch&response_type=token&locale=en"); err == nil { + jar.Cookies(resp.Request.URL) + body := ReturnJustString(io.ReadAll(resp.Body)) + var v, u string + if Data := Value.FindAllStringSubmatch(string(body), -1); len(Data) > 0 && len(Data[0]) > 0 { + v = Data[0][1] + } else { + fmt.Println("entered reauth for "+e, "Error occured From VALUE find") + returnDetails = MS_authentication(e, p, PS) + } + if Data := UrlPost.FindAllStringSubmatch(string(body), -1); len(Data) > 0 && len(Data[0]) > 0 { + u = Data[0][1] + } else { + fmt.Println("entered reauth for "+e, "Error occured from getting UrlPost") + returnDetails = MS_authentication(e, p, PS) + } + Client.Post(u, "application/x-www-form-urlencoded", bytes.NewReader([]byte(fmt.Sprintf("login=%v&loginfmt=%v&passwd=%v&PPFT=%v", url.QueryEscape(e), url.QueryEscape(e), url.QueryEscape(p), v)))) + if strings.Contains(redirect, "access_token") { + if d, err := Client.Post("https://user.auth.xboxlive.com/user/authenticate", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(User_Authenticate, strings.Split(strings.Split(strings.Split(redirect, "#")[1], "&")[0], "=")[1])))); err == nil { + var TOKEN string + Body := ReturnJustString(io.ReadAll(d.Body)) + if strings.Contains(Body, `"Token":"`) { + TOKEN = strings.Split(strings.Split(Body, `"Token":"`)[1], `"`)[0] + if x, err := Client.Post("https://xsts.auth.xboxlive.com/xsts/authorize", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(Xsts_Authenticate, TOKEN)))); err == nil { + x_data := ReturnJustString(io.ReadAll(x.Body)) + if x.StatusCode == 401 && strings.Contains(string(x_data), "XErr") { + switch true { + case strings.Contains(string(x_data), "2148916238"): + returnDetails = Info{Email: e, Password: p, Error: "Account belongs to someone under 18 and needs to be added to a family"} + return + case strings.Contains(string(x_data), "2148916233"): + returnDetails = Info{Email: e, Password: p, Error: "Account has no Xbox account, you must sign up for one first"} + return + } + } else { + if PS != nil { + var UHS, TOKEN string + if strings.Contains(string(x_data), `"uhs":"`) { + UHS = strings.Split(strings.Split(string(x_data), `"uhs":"`)[1], `"`)[0] + } else { + returnDetails = MS_authentication(e, p, PS) + return + } + if strings.Contains(string(x_data), `"Token":"`) { + TOKEN = strings.Split(strings.Split(string(x_data), `"Token":"`)[1], `"`)[0] + } else { + returnDetails = MS_authentication(e, p, PS) + return + } + req, _ := http.NewRequest("POST", "https://api.minecraftservices.com/authentication/login_with_xbox", bytes.NewBufferString(fmt.Sprintf(Login_With_Xbox, UHS, TOKEN))) + if resp, err := (&http.Client{Timeout: time.Second * 60, Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: PS.IP + ":" + PS.Port, User: url.UserPassword(PS.User, PS.Password)})}}).Do(req); err == nil { + switch resp.StatusCode { + case 200: + body, _ := io.ReadAll(resp.Body) + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(bytes.NewBuffer(body)))), &bearerMS) + Info_MCINFO, AccT := ReturnAll(bearerMS.Bearer_MS, PS) + returnDetails = Info{Info: Info_MCINFO, Bearer: bearerMS.Bearer_MS, AccessToken: strings.Split(strings.Split(redirect, "access_token=")[1], "&")[0], RefreshToken: strings.Split(strings.Split(redirect, "refresh_token=")[1], "&")[0], Expires: ReturnJustInt(strconv.Atoi(strings.Split(strings.Split(redirect, "expires_in=")[1], "&")[0])), Email: e, Password: p, AccountType: AccT} + case 429: + fmt.Printf("[%v] %v Has been ratelimited, sleeping for 1 minute..\n", resp.Status, e) + time.Sleep(60 * time.Second) + returnDetails = MS_authentication(e, p, PS) + default: + body, _ := io.ReadAll(resp.Body) + returnDetails = Info{Email: e, Password: p, Error: fmt.Sprintf("[%v] Unknown status code while authenticating.\n%v", resp.Status, string(body))} + } + } else { + returnDetails = Info{Email: e, Password: p, Error: err.Error()} + } + } else { + var UHS, TOKEN string + if strings.Contains(string(x_data), `"uhs":"`) { + UHS = strings.Split(strings.Split(string(x_data), `"uhs":"`)[1], `"`)[0] + } else { + returnDetails = MS_authentication(e, p, PS) + return + } + if strings.Contains(string(x_data), `"Token":"`) { + TOKEN = strings.Split(strings.Split(string(x_data), `"Token":"`)[1], `"`)[0] + } else { + returnDetails = MS_authentication(e, p, PS) + return + } + if resp, err := http.Post("https://api.minecraftservices.com/authentication/login_with_xbox", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(Login_With_Xbox, UHS, TOKEN)))); err == nil { + switch resp.StatusCode { + case 200: + body, _ := io.ReadAll(resp.Body) + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(bytes.NewBuffer(body)))), &bearerMS) + Info_MCINFO, AccT := ReturnAll(bearerMS.Bearer_MS, nil) + returnDetails = Info{Info: Info_MCINFO, Bearer: bearerMS.Bearer_MS, AccessToken: strings.Split(strings.Split(redirect, "access_token=")[1], "&")[0], RefreshToken: strings.Split(strings.Split(redirect, "refresh_token=")[1], "&")[0], Expires: ReturnJustInt(strconv.Atoi(strings.Split(strings.Split(redirect, "expires_in=")[1], "&")[0])), Email: e, Password: p, AccountType: AccT} + case 429: + fmt.Printf("[%v] %v Has been ratelimited, sleeping for 1 minute..\n", resp.Status, e) + time.Sleep(60 * time.Second) + returnDetails = MS_authentication(e, p, PS) + default: + body, _ := io.ReadAll(resp.Body) + returnDetails = Info{Email: e, Password: p, Error: fmt.Sprintf("[%v] Unknown status code while authenticating.\n%v", resp.Status, string(body))} + } + } else { + returnDetails = Info{Email: e, Password: p, Error: err.Error()} + } + } + } + } else { + returnDetails = Info{Email: e, Password: p, Error: err.Error()} + } + } else { + returnDetails = MS_authentication(e, p, PS) + } + } else { + returnDetails = Info{Email: e, Password: p, Error: err.Error()} + } + } else { + returnDetails = Info{Email: e, Password: p, Error: "Unable to authorize, access_token missing from request."} + } + } + } else { + returnDetails = MS_authentication(e, p, PS) + } + return +} + +func ReturnJustInt(i int, e error) int { + return i +} + +func ReturnJustString(data []byte, err error) string { + return string(data) +} + +func Remove(l []string, item string) (f []string) { + for _, other := range l { + if other != item { + f = append(f, other) + } + } + return +} + +func (s *Config) ToJson() (Data []byte, err error) { + return json.MarshalIndent(s, "", " ") +} + +func (config *Config) SaveConfig() { + if Json, err := config.ToJson(); err == nil { + WriteFile("config.json", string(Json)) + } +} + +func (s *Config) LoadState() { + data, err := ReadFile("config.json") + if err != nil { + s.LoadFromFile() + s.GcReq = 2 + s.MFAReq = 2 + s.SpreadPerReq = 40 + s.ChangeskinOnSnipe = true + s.ChangeSkinLink = "https://textures.minecraft.net/texture/516accb84322ca168a8cd06b4d8cc28e08b31cb0555eee01b64f9175cefe7b75" + s.SendMCSNAd = false + s.SaveConfig() + return + } + + json.Unmarshal([]byte(data), s) + s.LoadFromFile() +} + +func (c *Config) LoadFromFile() { + // Load a config file + + jsonFile, err := os.Open("config.json") + // if we os.Open returns an error then handle it + if err != nil { + jsonFile, _ = os.Create("config.json") + } + byteValue, _ := io.ReadAll(jsonFile) + json.Unmarshal(byteValue, &c) +} + +func WriteFile(path string, content string) { + os.WriteFile(path, []byte(content), 0644) +} + +func ReadFile(path string) ([]byte, error) { + return os.ReadFile(path) +} + +func Search(username string) (data Bux) { + if req, _ := http.Get("https://buxflip.com/data/search/" + username); req.StatusCode < 300 { + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(req.Body))), &data) + } + return +} + +type Headers struct { + Name string + Value string +} + +func GetReqStartedAndBuildHeaders(method, url string, body io.Reader, headers ...Headers) *http.Request { + req, _ := http.NewRequest(method, url, body) + for _, name := range headers { + req.Header.Add(name.Name, name.Value) + } + return req +} + +type UserINFO struct { + ID string `json:"id"` + Name string `json:"name"` +} + +func ReturnAll(bearer string, PS *ProxyMS) (Data UserINFO, Accounttype string) { + if PS != nil { + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile", nil) + req.Header.Add("Authorization", "Bearer "+bearer) + if resp, err := (&http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: PS.IP + ":" + PS.Port, User: url.UserPassword(PS.User, PS.Password)})}}).Do(req); err == nil { + switch resp.StatusCode { + case 200: + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &Data) + Accounttype = "Microsoft" + case 404: + Accounttype = "Giftcard" + } + } + } else { + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile", nil) + req.Header.Add("Authorization", "Bearer "+bearer) + if resp, err := http.DefaultClient.Do(req); err == nil { + switch resp.StatusCode { + case 200: + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &Data) + Accounttype = "Microsoft" + case 404: + Accounttype = "Giftcard" + } + } + } + return +} + +func CheckFiles() { + _, err := os.Open("accounts.txt") + if os.IsNotExist(err) { + os.Create("accounts.txt") + } + + _, err = os.Open("proxys.txt") + if os.IsNotExist(err) { + os.Create("proxys.txt") + } + + _, err = os.Open("names.txt") + if os.IsNotExist(err) { + os.Create("names.txt") + } + + _, err = os.Stat("cropped") + if os.IsNotExist(err) { + os.MkdirAll("cropped/logs", 0755) + } +} + +func Clear() { + if runtime.GOOS == "windows" { + cmd := exec.Command("cmd", "/c", "cls") + cmd.Stdout = os.Stdout + cmd.Run() + } else { + cmd := exec.Command("clear") + cmd.Stdout = os.Stdout + cmd.Run() + } +} + +func ThreeLetters(option string) (Data []NameRequest) { + var data Bux2 + switch option { + case "3c": + resp, _ := http.Get("https://buxflip.com/data/3c") + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &data) + Data = data.Data + case "3l": + resp, _ := http.Get("https://buxflip.com/data/3c?3l") + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &data) + Data = data.Data + case "3n": + resp, _ := http.Get("https://buxflip.com/data/3c?3n") + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &data) + Data = data.Data + } + return +} diff --git a/packages/apiGO/ping.go b/packages/apiGO/ping.go new file mode 100644 index 0000000..29aedf6 --- /dev/null +++ b/packages/apiGO/ping.go @@ -0,0 +1,20 @@ +package apiGO + +import ( + "crypto/tls" + "time" +) + +func PingMC() float64 { + var pingTimes float64 + conn, _ := tls.Dial("tcp", "api.minecraftservices.com:443", nil) + defer conn.Close() + for i := 0; i < 10; i++ { + recv := make([]byte, 4096) + time1 := time.Now() + conn.Write([]byte("PUT /minecraft/profile/name/test HTTP/1.1\r\nHost: api.minecraftservices.com\r\nAuthorization: Bearer TestToken\r\n\r\n")) + conn.Read(recv) + pingTimes += float64(time.Since(time1).Milliseconds()) + } + return float64(pingTimes/10000) * 5000 +} diff --git a/packages/apiGO/proxy.go b/packages/apiGO/proxy.go new file mode 100644 index 0000000..af0a125 --- /dev/null +++ b/packages/apiGO/proxy.go @@ -0,0 +1,111 @@ +package apiGO + +import ( + "bufio" + "crypto/tls" + "crypto/x509" + "fmt" + "math/rand" + "os" + "strings" + "sync" + "time" + + "golang.org/x/net/proxy" +) + +func (Proxy *Proxys) GetProxys(uselist bool, list []string) { + Proxy.Proxys = []string{} + if uselist { + Proxy.Proxys = append(Proxy.Proxys, list...) + } else { + file, err := os.Open("proxys.txt") + if err == nil { + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + Proxy.Proxys = append(Proxy.Proxys, scanner.Text()) + } + } + } +} + +func (Proxy *Proxys) CompRand() string { + rand.Seed(time.Now().UnixNano()) + time.Sleep(10 * time.Millisecond) + return Proxy.Proxys[rand.Intn(len(Proxy.Proxys))] +} + +func (Proxy *Proxys) Setup() { + Proxy.Used = make(map[string]bool) + for _, proxy := range Proxy.Proxys { + Proxy.Used[proxy] = false + } +} + +func (Proxy *Proxys) RandProxy() string { + for _, proxy := range Proxy.Proxys { + if !Proxy.Used[proxy] { + Proxy.Used[proxy] = true + return proxy + } + } + + Proxy.Setup() + + return "" +} + +func (Bearers *MCbearers) GenSocketConns(Proxy ReqConfig) (pro []Proxys) { + var Accs [][]Info + var incr int + var use int + roots := x509.NewCertPool() + roots.AppendCertsFromPEM(ProxyByte) + + for _, Acc := range Bearers.Details { + if len(Accs) == 0 { + Accs = append(Accs, []Info{ + Acc, + }) + } else { + if incr == 3 { + incr = 0 + use++ + Accs = append(Accs, []Info{}) + } + Accs[use] = append(Accs[use], Acc) + } + incr++ + } + + var wg sync.WaitGroup + for _, Accs := range Accs { + wg.Add(1) + go func(Accs []Info) { + var user, pass, ip, port string + auth := strings.Split(Proxy.Proxys.RandProxy(), ":") + ip, port = auth[0], auth[1] + if len(auth) > 2 { + user, pass = auth[2], auth[3] + } + req, err := proxy.SOCKS5("tcp", fmt.Sprintf("%v:%v", ip, port), &proxy.Auth{ + User: user, + Password: pass, + }, proxy.Direct) + if err == nil { + conn, err := req.Dial("tcp", "api.minecraftservices.com:443") + if err == nil { + pro = append(pro, Proxys{ + Accounts: Accs, + Conn: tls.Client(conn, &tls.Config{RootCAs: roots, InsecureSkipVerify: true, ServerName: "api.minecraftservices.com"}), + }) + } + } + wg.Done() + }(Accs) + } + + wg.Wait() + return +} diff --git a/packages/apiGO/send.go b/packages/apiGO/send.go new file mode 100644 index 0000000..4cc86fd --- /dev/null +++ b/packages/apiGO/send.go @@ -0,0 +1,94 @@ +package apiGO + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "sort" + "sync" + "time" +) + +func (Data *ReqConfig) SnipeReq(Acc Config) (data SentRequests) { + var wg sync.WaitGroup + + for time.Now().Before(time.Unix(Data.Droptime, 0).Add(-time.Second * 10)) { + time.Sleep(time.Second * 1) + } + + if Data.Proxy { + Clients := Data.Bearers.GenSocketConns(*Data) + time.Sleep(time.Until(time.Unix(Data.Droptime, 0).Add(time.Millisecond * time.Duration(0-Data.Delay)).Add(time.Duration(-float64(time.Since(time.Now()).Nanoseconds())/1000000.0) * time.Millisecond))) + for _, config := range Clients { + wg.Add(1) + go func(config Proxys) { + var wgs sync.WaitGroup + for _, Acc := range config.Accounts { + if Acc.AccountType == "Giftcard" { + for i := 0; i < Acc.Requests; i++ { + wgs.Add(1) + go func(Account Info, payloads string) { + data.Requests = append(data.Requests, Details{ + ResponseDetails: SocketSending(config.Conn, payloads), + Bearer: Account.Bearer, + Email: Account.Email, + Type: Account.AccountType, + }) + wgs.Done() + }(Acc, fmt.Sprintf("POST /minecraft/profile HTTP/1.1\r\nHost: api.minecraftservices.com\r\nConnection: open\r\nContent-Length:%v\r\nContent-Type: application/json\r\nAccept: application/json\r\nAuthorization: Bearer %v\r\n\r\n{\"profileName\":\"%v\"}\r\n", len(`{"profileName":"`+Data.Name+`"}`), Acc.Bearer, Data.Name)) + } + } else { + for i := 0; i < Acc.Requests; i++ { + wgs.Add(1) + go func(Account Info, payloads string) { + data.Requests = append(data.Requests, Details{ + ResponseDetails: SocketSending(config.Conn, payloads), + Bearer: Account.Bearer, + Email: Account.Email, + Type: Account.AccountType, + Password: Account.Password, + }) + wgs.Done() + }(Acc, "PUT /minecraft/profile/name/"+Data.Name+" HTTP/1.1\r\nHost: api.minecraftservices.com\r\nConnection: open\r\nUser-Agent: MCSN/1.0\r\nAuthorization: bearer "+Acc.Bearer+"\r\n\r\n") + } + } + } + wgs.Wait() + wg.Done() + }(config) + } + } else { + payload := Data.Bearers.CreatePayloads(Data.Name) + conn, _ := tls.Dial("tcp", "api.minecraftservices.com:443", nil) + time.Sleep(time.Until(time.Unix(Data.Droptime, 0).Add(time.Millisecond * time.Duration(0-Data.Delay)).Add(time.Duration(-float64(time.Since(time.Now()).Nanoseconds())/1000000.0) * time.Millisecond))) + for e, Account := range Data.Bearers.Details { + for i := 0; i < Account.Requests; i++ { + wg.Add(1) + go func(e int, Account Info) { + data.Requests = append(data.Requests, Details{ + ResponseDetails: SocketSending(conn, payload.Payload[e]), + Bearer: Account.Bearer, + Email: Account.Email, + Type: Account.AccountType, + }) + wg.Done() + }(e, Account) + time.Sleep(time.Duration(Acc.SpreadPerReq) * time.Microsecond) + } + } + } + + wg.Wait() + fmt.Println() + + sort.Slice(data.Requests, func(i, j int) bool { + return data.Requests[i].ResponseDetails.SentAt.Before(data.Requests[j].ResponseDetails.SentAt) + }) + + return +} + +func JsonValue(f interface{}) []byte { + g, _ := json.Marshal(f) + return g +} diff --git a/packages/apiGO/var.go b/packages/apiGO/var.go new file mode 100644 index 0000000..7e648d8 --- /dev/null +++ b/packages/apiGO/var.go @@ -0,0 +1,170 @@ +package apiGO + +import ( + "crypto/tls" + "time" +) + +var ( + ProxyByte = []byte(` + -- GlobalSign Root R2, valid until Dec 15, 2021 + -----BEGIN CERTIFICATE----- + MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G + A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp + Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 + MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG + A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI + hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL + v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 + eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq + tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd + C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa + zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB + mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH + V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n + bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG + 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs + J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO + 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS + ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd + AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 + TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== + -----END CERTIFICATE-----`) +) + +type Name struct { + Names string `json:"name"` + Drop float64 `json:"droptime"` +} + +type Proxys struct { + Proxys []string + Used map[string]bool + Accounts []Info + Conn *tls.Conn +} + +type Resp struct { + SentAt time.Time + RecvAt time.Time + StatusCode string + Body string +} + +type Payload struct { + Payload []string + Conns []*tls.Conn + + Start int64 `json:"unix"` + End int64 `json:"unix_end"` +} + +type ServerInfo struct { + Webhook string + SkinUrl string +} + +type mojangData struct { + Bearer_MS string `json:"access_token"` + Expires int `json:"expires_in"` +} + +type MCbearers struct { + Details []Info +} + +type Info struct { + Bearer string + RefreshToken string + AccessToken string + Expires int + AccountType string + Email string + Password string + Requests int + Error string + Info UserINFO +} + +type Config struct { + ChangeSkinLink string `json:"ChangeSkinLink"` + ChangeskinOnSnipe bool `json:"ChangeskinOnSnipe"` + GcReq int `json:"GcReq"` + MFAReq int `json:"MFAReq"` + ManualBearer bool `json:"ManualBearer"` + SpreadPerReq int `json:"SpreadPerReq"` + SendMCSNAd bool `json:"SendMCSN_MsgUponBMJoin"` + AlwaysUseUnix bool `json:"forceuseunix"` + + Bearers []Bearers `json:"Bearers"` + Logs []Logs `json:"logs"` +} + +type Logs struct { + Email string `json:"email"` + Password string `json:"password"` + Send time.Time `json:"send"` + Recv time.Time `json:"recv"` + Success bool `json:"success"` + Name string `json:"name"` +} + +type Bearers struct { + Bearer string `json:"Bearer"` + Email string `json:"Email"` + Password string `json:"Password"` + AuthInterval int64 `json:"AuthInterval"` + AuthedAt int64 `json:"AuthedAt"` + Type string `json:"Type"` + NameChange bool `json:"NameChange"` +} + +type Bux2 struct { + Action string `json:"action"` + Desc string `json:"desc"` + Code string `json:"code"` + ID string `json:"id"` + Error string `json:"error"` + Data []NameRequest `json:"data"` +} + +type Bux struct { + Action string `json:"action"` + Desc string `json:"desc"` + Code string `json:"code"` + ID string `json:"id"` + Error string `json:"error"` + Data NameRequest `json:"data"` +} + +type NameRequest struct { + Status string `json:"status,omitempty"` + Searches string `json:"searches,omitempty"` + Start int64 `json:"begin,omitempty"` + End int64 `json:"end,omitempty"` + HeadURL string `json:"headurl,omitempty"` + Error string `json:"error,omitempty"` +} + +type ReqConfig struct { + Name string + Delay float64 + Droptime int64 + Proxys Proxys + Bearers MCbearers + UseUnix bool + + Proxy bool +} + +type SentRequests struct { + Requests []Details +} + +type Details struct { + ResponseDetails Resp + Bearer string + Email string + Password string + Type string +} diff --git a/packages/h2/client.go b/packages/h2/client.go new file mode 100644 index 0000000..81aaaa8 --- /dev/null +++ b/packages/h2/client.go @@ -0,0 +1,115 @@ +package h2 + +import ( + "fmt" + "net/url" + "strings" + + tls "github.com/bogdanfinn/utls" + "golang.org/x/net/http2" +) + +type Conn struct { + Url *url.URL + Conn *http2.Framer + UnderlyingConn *tls.UConn + Config ReqConfig + Client *Client + FirstUse bool +} + +// Connects to the url you supply, and stores it inside the Client struct. +func (Data *Client) Connect(addr string, config ReqConfig) (Connection Conn, err error) { + Connection.Url = GrabUrl(addr) + Connection.Client = Data + Connection.Config = config + if err := Connection.GenerateConn(config); err != nil { + return Conn{}, err + } + return Connection, nil +} + +// Does a request, since http2 doesnt like to resent new headers. after the first request it will reconnect to the server +// and make a new http2 framer variable to use. +func (Data *Conn) Do(method, json, content_type string, cookies *[]string) (Config Response, err error) { + if !Data.FirstUse { + Data.FirstUse = true + } else { + if err = Data.GenerateConn(Data.Config); err != nil { + return Response{}, err + } + } + + if cookies != nil { + Data.Client.Config.Headers["cookie"] += TurnCookieHeader(*cookies) + } + + var FoundAndSent bool + + Headers := Data.GetHeaders(method) + + if method != "GET" { + var FoundType, FoundLength, FoundEither bool + for _, header := range Headers { + if strings.Contains(header, "content-type") { + FoundType = true + } + if strings.Contains(header, "content-length") { + FoundLength = true + } + } + if !FoundLength { + Data.AddHeader("content-length", fmt.Sprintf("%v", len(json))) + FoundEither = true + } + if !FoundType { + if content_type != "" { + Data.AddHeader("content-type", content_type) + } + FoundEither = true + } + if FoundEither { + Headers = Data.GetHeaders(method) + Data.SendHeaders(Headers, method == "GET") + FoundAndSent = true + } + Data.DataSend([]byte(json)) + } + if !FoundAndSent { + Data.SendHeaders(Headers, method == "GET") + } + resp, err := Data.FindData() + if err != nil { + return resp, err + } + if resp.Status == "302" || resp.Status == "301" { + Data.Url.Path = GetHeaderVal("location", resp.Headers).Value + if err = Data.GenerateConn(Data.Config); err != nil { + return Response{}, err + } + Data.SendHeaders(Data.GetHeaders(method), method == "GET") + return Data.FindData() + } + return resp, err +} + +func (Data *Conn) ChangeProxy(proxy *ProxyAuth) { + Data.Config.Proxy = proxy +} + +// Changes the url path, so you can send to different locations under one variable. +func (Data *Conn) ChangeURL(url *url.URL) { + Data.Url = url +} + +// adds a header to the client struct +func (Data *Conn) AddHeader(name, value string) { + Data.Client.Config.Headers[name] = value +} + +// deletes headers from a client struct +func (Data *Conn) DeleteHeader(headernames ...string) { + for _, val := range headernames { + delete(Data.Client.Config.Headers, val) + } +} diff --git a/packages/h2/utils.go b/packages/h2/utils.go new file mode 100644 index 0000000..bb13e6f --- /dev/null +++ b/packages/h2/utils.go @@ -0,0 +1,384 @@ +package h2 + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "net" + "net/url" + "strings" + + tls "github.com/bogdanfinn/utls" + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" +) + +func (Data *Conn) Connect(config ReqConfig) (net.Conn, bool, error) { + if conn, err := net.Dial("tcp", fmt.Sprintf("%v:%v", config.Proxy.IP, config.Proxy.Port)); err == nil { + Conn_URL := CheckAddr(Data.Url) + if config.Proxy.User != "" && config.Proxy.Password != "" { + conn.Write([]byte(fmt.Sprintf("CONNECT %v HTTP/1.1\r\nHost: %v\r\nProxy-Authorization: Basic %v\r\nProxy-Connection: keep-alive\r\nUser-Agent: MCSN/1.1\r\n\r\n", Conn_URL, Conn_URL, base64.RawStdEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v", config.Proxy.User, config.Proxy.Password)))))) + } else { + conn.Write([]byte(fmt.Sprintf("CONNECT %v HTTP/1.1\r\nHost: %v\r\nProxy-Connection: keep-alive\r\nUser-Agent: MCSN/1.1\r\n\r\n", Conn_URL, Conn_URL))) + } + var junk = make([]byte, 4096) + conn.Read(junk) + switch Status := string(junk); Status[9:12] { + case "200": + return conn, true, nil + case "407": + return nil, false, errors.New(fmt.Sprintf("[%v] Proxy <%v> Failed to authorize: Username/Password invalid.\n", Status[9:12], config.Proxy.IP)) + default: + return nil, false, errors.New(fmt.Sprintf("[%v] Proxy <%v> Failed to authorize: Unknown Statuscode.\n", Status[9:12], config.Proxy.IP)) + } + } + return nil, false, errors.New(fmt.Sprintf("Proxy <%v> Failed to authorize: Unknown Error EOF\n", config.Proxy.IP)) +} + +// Generate conn performs a conn to the url you supply. +func (Data *Conn) GenerateConn(config ReqConfig) (err error) { + if config.DataBodyMaxLength == 0 { + return errors.New("error: [DataBodyMaxLength] cannot be 0, suggested value to be above 130000") + } + + var conn net.Conn + var tlsConn *tls.UConn + if config.Proxy != nil { + var ok bool + var err error + conn, ok, err = Data.Connect(config) + if !ok && err != nil { + return err + } + } else { + conn, err = net.Dial("tcp", CheckAddr(Data.Url)) + if err != nil { + return err + } + } + + tlsConn = tls.UClient(conn, &tls.Config{ + ServerName: Data.Url.Host, + NextProtos: Data.Client.Config.Protocols, + InsecureSkipVerify: config.InsecureSkipVerify, + Renegotiation: config.Renegotiation, + PreferServerCipherSuites: config.PreferServerCipherSuites, + RootCAs: config.RootCAs, + ClientCAs: config.ClientCAs, + }, config.BuildID, true, config.UseHTTP1) + + if config.SaveCookies { + if Data.Client.Cookies == nil || len(Data.Client.Cookies) == 0 { + Data.Client.Cookies = make(map[string][]hpack.HeaderField) + } + } + + fmt.Fprintf(tlsConn, http2.ClientPreface) + + if err = tlsConn.Handshake(); err != nil { + return err + } + + Data.Conn = http2.NewFramer(tlsConn, tlsConn) + Data.Conn.SetReuseFrames() + Data.WriteSettings(config.DataBodyMaxLength) + Data.Windows_Update() + Data.Send_Prio_Frames() + Data.UnderlyingConn = tlsConn + return nil +} + +// gets a selected cookie based on the cookie_name variable +// +// e.g. "__vf_bm" > "__vf_bm=awdawd223reqfqh32rqrf32qr" +func (Data *Conn) GetCookie(cookie_name, url string) string { + for _, val := range Data.Client.Cookies[url] { + if strings.Contains(val.Value, cookie_name) { + Cookie := strings.Split(val.Value, "=") + return fmt.Sprintf("%v=%v", Cookie[0], Cookie[1]) + } + } + + return "" +} + +// Gets a header value based on the name you supply. +func GetHeaderVal(name string, headers []hpack.HeaderField) hpack.HeaderField { + for _, data := range headers { + if data.Name == name { + return data + } + } + return hpack.HeaderField{} +} + +// This is a helper function that gets all the cookies from a +// cached url and returns them in a format that works with the cookie: header. +func (Data *Conn) TransformCookies(url string) string { + var cookies []string + for _, val := range Data.Client.Cookies[url] { + cookie_name := strings.Split(strings.Split(val.Value, ";")[0], "=") + cookies = append(cookies, fmt.Sprintf("%v=%v", cookie_name[0], cookie_name[1])) + } + return strings.Join(cookies, "; ") +} + +// strings.Join shortcut to turn your list of coookies into a cookie: header format. +func TurnCookieHeader(Cookies []string) string { + return strings.Join(Cookies, "; ") +} + +// Sends data through the framer +func (Data *Conn) DataSend(body []byte) { + Data.Conn.WriteData(uint32(Data.Config.ID), true, body) +} + +// Sends priority frames, this ensures the right data is sent in the correct order. +func (Data *Conn) Send_Prio_Frames() { + Data.Conn.WritePriority(3, http2.PriorityParam{ + StreamDep: 0, + Weight: 200, + Exclusive: false, + }) + + Data.Conn.WritePriority(5, http2.PriorityParam{ + StreamDep: 0, + Weight: 100, + Exclusive: false, + }) + + Data.Conn.WritePriority(7, http2.PriorityParam{ + StreamDep: 0, + Weight: 0, + Exclusive: false, + }) + + Data.Conn.WritePriority(9, http2.PriorityParam{ + StreamDep: 7, + Weight: 0, + Exclusive: false, + }) + + Data.Conn.WritePriority(11, http2.PriorityParam{ + StreamDep: 3, + Weight: 0, + Exclusive: false, + }) + + Data.Conn.WritePriority(13, http2.PriorityParam{ + StreamDep: 0, + Weight: 240, + Exclusive: false, + }) +} + +// Loops over the Config headers and applies them to the Client []string variable. +// Method for example "GET". +func (Data *Conn) GetHeaders(method string) (headers []string) { + for _, name := range Data.Client.Config.HeaderOrder { + switch name { + case ":authority": + headers = append(headers, name+": "+Data.Url.Host) + case ":method": + headers = append(headers, name+": "+method) + case ":path": + headers = append(headers, name+": "+CheckQuery(Data.Url)) + case ":scheme": + headers = append(headers, name+": "+Data.Url.Scheme) + default: + if val, exists := Data.Client.Config.Headers[name]; exists { + headers = append(headers, name+": "+val) + } + } + } + + for name, val := range Data.Client.Config.Headers { + if !strings.Contains(strings.Join(Data.Client.Config.HeaderOrder, ","), name) { + headers = append(headers, name+": "+val) + } + } + + return +} + +// Writes the headers to the http2 framer. +// this function also encodes the headers into a []byte +// Endstream is also called in this function, only use true values when performing GET requests. +func (Data *Conn) SendHeaders(headers []string, endStream bool) { + Data.Conn.WriteHeaders( + http2.HeadersFrameParam{ + StreamID: uint32(Data.Config.ID), + BlockFragment: Data.FormHeaderBytes(headers), + EndHeaders: true, + EndStream: endStream, + }, + ) +} + +// Writes the window update frame to the http2 framer. +func (Data *Conn) Windows_Update() { + Data.Conn.WriteWindowUpdate(0, 12517377) +} + +// Write settings writes the default chrome settings to the framer +func (Data *Conn) WriteSettings(ResponseDataSize uint32) { + Data.Conn.WriteSettings( + http2.Setting{ + ID: http2.SettingHeaderTableSize, Val: 65536, + }, + http2.Setting{ + ID: http2.SettingEnablePush, Val: 1, + }, + http2.Setting{ + ID: http2.SettingMaxConcurrentStreams, Val: 1000, + }, + http2.Setting{ + ID: http2.SettingInitialWindowSize, Val: ResponseDataSize, + }, + http2.Setting{ + ID: http2.SettingMaxFrameSize, Val: 16384, + }, + http2.Setting{ + ID: http2.SettingMaxHeaderListSize, Val: 262144, + }, + ) +} + +// Find data is called after the prior settings/window/prio frames are performed, it goes through the +// framer and returns its data, any errors and also headers / status codes. +func (Datas *Conn) FindData() (Config Response, err error) { + for { + f, err := Datas.Conn.ReadFrame() + if err != nil { + return Config, err + } + switch f := f.(type) { + case *http2.DataFrame: + Config.Data = append(Config.Data, f.Data()...) + if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) { + return Config, nil + } + case *http2.HeadersFrame: + Config.Headers, err = hpack.NewDecoder(Datas.Config.DataBodyMaxLength, nil).DecodeFull(f.HeaderBlockFragment()) + if err != nil { + return Config, err + } + for _, Data := range Config.Headers { + switch Data.Name { + case ":status": + Config.Status = Data.Value + case "set-cookie": + if Datas.Config.SaveCookies { + Datas.Client.Cookies[Datas.Url.String()] = append(Datas.Client.Cookies[Datas.Url.String()], Data) + } + } + } + if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) && f.FrameHeader.Flags.Has(http2.FlagHeadersEndStream) { + return Config, nil + } + case *http2.RSTStreamFrame: + return Config, errors.New(f.ErrCode.String()) + case *http2.GoAwayFrame: + return Config, errors.New(f.ErrCode.String()) + } + } +} + +// Turns the addr into a url.URL variable. +func GrabUrl(addr string) *url.URL { + URL, _ := url.Parse(addr) + if URL.Path == "" { + URL.Path = "/" + } + return URL +} + +// Checks if there are params in your url and adds it to your path. +// +// e.g. "/api/name?code=12343&scope=1234" +func CheckQuery(Data *url.URL) string { + if Data.Query().Encode() != "" { + return Data.Path + "?" + Data.Query().Encode() + } + return Data.Path +} + +// Form header bytes takes the []string of headers and turns it into []byte data +// this is so it can be compatiable for the http2 headers. +func (Data *Conn) FormHeaderBytes(headers []string) []byte { + var val []string + hbuf := bytes.NewBuffer([]byte{}) + encoder := hpack.NewEncoder(hbuf) + for _, header := range headers { + switch data := strings.Split(header, ":"); len(data) { + case 3: + val = data[1:] + val[0] = fmt.Sprintf(":%v", val[0]) + default: + val = data[0:] + } + encoder.WriteField(hpack.HeaderField{Name: strings.TrimSpace(val[0]), Value: strings.TrimSpace(val[1])}) + } + return hbuf.Bytes() +} + +// Takes in the url and returns the host + port of the url. +// +// e.g. "www.google.com:443" +func CheckAddr(url *url.URL) string { + switch url.Scheme { + case "https": + return url.Host + ":443" + default: + return url.Host + ":80" + } +} + +// This returns the default config variables. +// header order, chrome like headers and protocols. +func GetDefaultConfig() Config { + return Config{ + HeaderOrder: []string{ + ":authority", + ":method", + ":path", + ":scheme", + "accept", + "accept-encoding", + "accept-language", + "cache-control", + "content-length", + "content-type", + "cookie", + "origin", + "referer", + "sec-ch-ua", + "sec-ch-ua-mobile", + "sec-ch-ua-platform", + "sec-ch-ua-platform-version", + "upgrade-insecure-requests", + "user-agent", + "sec-fetch-site", + "sec-fetch-mode", + "sec-fetch-user", + "sec-fetch-dest", + }, + Headers: map[string]string{ + "cache-control": "max-age=0", + "upgrade-insecure-requests": "1", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", + "accept": "application/json, text/javascript, text/html, application/xhtml+xml, application/xml;q=0.9, image/avif, image/webp, image/apng, */*;q=0.8, application/signed-exchange;v=b3", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-user": "?1", + "sec-fetch-dest": "empty", + "sec-ch-ua": `"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"`, + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\\\"Windows\\", + "sec-ch-ua-platform-version": "14.0.0", + "accept-language": "en-US,en;q=0.9", + }, + Protocols: []string{"h2", "h1", "http/1.1"}, + } +} diff --git a/packages/h2/variables.go b/packages/h2/variables.go new file mode 100644 index 0000000..39173da --- /dev/null +++ b/packages/h2/variables.go @@ -0,0 +1,71 @@ +package h2 + +import ( + "crypto/x509" + + tls "github.com/bogdanfinn/utls" + + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" +) + +const ( + MethodGet = "GET" + MethodPost = "POST" + MethodPut = "PUT" + MethodOptions = "OPTIONS" + MethodDelete = "DELETE" + MethodConnect = "CONNECT" +) + +type Client struct { + Config Config + Cookies map[string][]hpack.HeaderField // Used to store the data of websites cookies +} + +type Debug struct { + Headers []string `json:"sentheaders"` + HeadersRecv []string `json:"recvheaders"` + SentFrames []Frames `json:"send"` + RecvFrames []Frames `json:"recv"` +} + +type Frames struct { + StreamID uint32 `json:"streamid"` + Setting string `json:"name"` + Length uint32 `json:"len"` +} + +type Website struct { + Conn *http2.Framer + Config ReqConfig + HasDoneFirstReq bool +} + +type Config struct { + HeaderOrder, Protocols []string + Headers map[string]string +} + +type Response struct { + Data []byte + Status string + Headers []hpack.HeaderField +} + +type ReqConfig struct { + ID int64 // StreamID for requests (Multiplexing) + BuildID tls.ClientHelloID // HelloChrome_100 etc + DataBodyMaxLength uint32 + Renegotiation tls.RenegotiationSupport + InsecureSkipVerify bool + Proxy *ProxyAuth + SaveCookies bool + PreferServerCipherSuites bool + RootCAs, ClientCAs *x509.CertPool + UseHTTP1 bool +} + +type ProxyAuth struct { + IP, Port, User, Password string +} diff --git a/packages/utils/auth.go b/packages/utils/auth.go new file mode 100644 index 0000000..0632d4e --- /dev/null +++ b/packages/utils/auth.go @@ -0,0 +1,799 @@ +package utils + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strings" + "sync" + "time" + "unicode" + + "main/packages/apiGO" + + "github.com/Tnze/go-mc/bot" + "github.com/Tnze/go-mc/bot/basic" + "github.com/Tnze/go-mc/bot/msg" + "github.com/Tnze/go-mc/bot/playerlist" + "github.com/Tnze/go-mc/bot/screen" + "github.com/Tnze/go-mc/bot/world" + "github.com/Tnze/go-mc/chat" +) + +type Proxys_Accs struct { + Proxy string + Accs []apiGO.Info +} + +var Accs map[string][]Proxys_Accs = make(map[string][]Proxys_Accs) +var Use_gc, Accamt int +var First_gc bool = true + +func AuthAccs() { + grabDetails() + if len(Con.Bearers) == 0 { + fmt.Println(Logo("No Bearers have been found, please check your details.")) + return + } else { + checkifValid() + for _, Accs := range Con.Bearers { + if Accs.NameChange { + Bearer.Details = append(Bearer.Details, apiGO.Info{ + Bearer: Accs.Bearer, + AccountType: Accs.Type, + Email: Accs.Email, + Password: Accs.Password, + Info: apiGO.UserINFO(Accs.Info), + }) + } + } + } +} + +func grabDetails() { + + var AccountsVer []string + file, _ := os.Open("accounts.txt") + + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + AccountsVer = append(AccountsVer, scanner.Text()) + } + + if len(AccountsVer) == 0 { + fmt.Println(Logo("Unable to continue, you have no Accounts added.")) + return + } + P := Payload(AccountsVer) + CheckDupes(AccountsVer) + if Con.Bearers == nil { + P_Auth(P, false) + } else if len(Con.Bearers) < len(AccountsVer) { + var auth []string + check := make(map[string]bool) + for _, Acc := range Con.Bearers { + check[Acc.Email+":"+Acc.Password] = true + } + for _, Accs := range AccountsVer { + if !check[Accs] { + auth = append(auth, Accs) + } + } + P_Auth(Payload(auth), false) + } else if len(AccountsVer) < len(Con.Bearers) { + var New []Bearers + for _, Accs := range AccountsVer { + for _, num := range Con.Bearers { + if Accs == num.Email+":"+num.Password { + New = append(New, num) + break + } + } + } + Con.Bearers = New + } + + Con.SaveConfig() + Con.LoadState() +} + +func checkifValid() { + var reAuth []string + var wgs sync.WaitGroup + for _, Accs := range Con.Bearers { + if time.Now().Unix() > Accs.AuthedAt+Accs.AuthInterval { + reAuth = append(reAuth, Accs.Email+":"+Accs.Password) + } else { + if Accs.NameChange { + wgs.Add(1) + go func(Accs Bearers) { + f, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile/name/boom/available", nil) + f.Header.Set("Authorization", "Bearer "+Accs.Bearer) + if j, err := http.DefaultClient.Do(f); err == nil { + if j.StatusCode == 401 { + reAuth = append(reAuth, Accs.Email+":"+Accs.Password) + } + } + wgs.Done() + }(Accs) + } + } + } + wgs.Wait() + if len(reAuth) != 0 { + P_Auth(Payload(reAuth), true) + } + Con.SaveConfig() + Con.LoadState() +} + +// _diamondburned_#4507 thanks to them for the epic example below. + +func CheckDupes(strs []string) []string { + dedup := strs[:0] // re-use the backing array + track := make(map[string]bool, len(strs)) + + for _, str := range strs { + if track[str] { + continue + } + dedup = append(dedup, str) + track[str] = true + } + + return dedup +} + +func CheckAccs() { + for { + time.Sleep(10 * time.Second) + var reauth []string + for _, acc := range Con.Bearers { + if time.Now().Unix() > acc.AuthedAt+acc.AuthInterval && acc.NameChange { + reauth = append(reauth, acc.Email+":"+acc.Password) + } + } + if len(reauth) > 0 { + P_Auth(Payload(reauth), true) + } + Con.SaveConfig() + Con.LoadState() + } +} + +type Payload_auth struct { + Proxy string + Accounts []string +} + +func Payload(accounts []string) (Data []Payload_auth) { + var use_proxy, ug int + var f bool = true + for _, bearer := range accounts { + if use_proxy >= len(Proxy.Proxys) && len(Proxy.Proxys) < len(Bearer.Details) { + break + } + + if f { + Data = append(Data, Payload_auth{Proxy: Proxy.Proxys[use_proxy]}) + f = false + use_proxy++ + } + if len(Data[ug].Accounts) != 3 { + Data[ug].Accounts = append(Data[ug].Accounts, bearer) + } else { + ug++ + Data = append(Data, Payload_auth{Proxy: Proxy.Proxys[use_proxy], Accounts: []string{bearer}}) + use_proxy++ + } + } + return +} + +var ( + client *bot.Client + player *basic.Player + chatHandler *msg.Manager + worldManager *world.World + screenManager *screen.Manager +) + +func Namemc_key(bearer string) string { + + var Info_Acc apiGO.UserINFO + + if len(Proxy.Proxys) > 0 { + p := Proxy.CompRand() + info := strings.Split(p, ":") + var ip, port, user, pass string + switch len(info) { + case 2: + ip = info[0] + port = info[1] + case 4: + ip = info[0] + port = info[1] + user = info[2] + pass = info[3] + } + Info_Acc, _ = apiGO.ReturnAll(bearer, &apiGO.ProxyMS{IP: ip, Port: port, User: user, Password: pass}) + } else { + Info_Acc, _ = apiGO.ReturnAll(bearer, nil) + } + + client = bot.NewClient() + client.Auth = bot.Auth{ + Name: Info_Acc.Name, + UUID: Info_Acc.ID, + AsTk: bearer, + } + + var P *basic.Player + L := basic.NewPlayer(client, basic.DefaultSettings, basic.EventsListener{ + GameStart: func() error { + + return nil + }, + Disconnect: func(reason chat.Message) error { + return nil + }, + Death: func() error { + return P.Respawn() + }, + }) + P = L + chatHandler = msg.New(client, P, playerlist.New(client), msg.EventsHandler{ + SystemChat: func(c chat.Message, overlay bool) error { + if Text := c.ClearString(); NotWhiteSpace(Text) { + if strings.Contains(Text, Info_Acc.Name+" joined the game.") { + if err := chatHandler.SendMessage("/namemc"); err != nil { + client.Close() + return err + } + } else if strings.Contains(Text, "https://namemc.com/claim?key=") { + key := Text + client.Close() + return errors.New("got-key:" + key) + } + } + return nil + }, + PlayerChatMessage: func(msg chat.Message, validated bool) error { + return nil + }, + DisguisedChat: func(msg chat.Message) error { + return nil + }, + }) + if err := client.JoinServer("blockmania.com"); err == nil { + for { + if err := client.HandleGame(); err == nil { + panic("HandleGame never return nil") + } else if strings.Contains(err.Error(), "got-key") { + return strings.Split(err.Error(), "got-key:")[1] + } + } + } else { + return err.Error() + } +} + +func NotWhiteSpace(str string) bool { + for _, c := range str { + if !unicode.IsSpace(c) { + return true + } + } + return false +} + +func ReturnAll(bearer string, PS *apiGO.ProxyMS) (Data apiGO.UserINFO, Accounttype string) { + if PS != nil { + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile", nil) + req.Header.Add("Authorization", "Bearer "+bearer) + if resp, err := (&http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: PS.IP + ":" + PS.Port, User: url.UserPassword(PS.User, PS.Password)})}}).Do(req); err == nil { + switch resp.StatusCode { + case 200: + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &Data) + Accounttype = "Microsoft" + case 404: + Accounttype = "Giftcard" + } + } + } else { + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile", nil) + req.Header.Add("Authorization", "Bearer "+bearer) + if resp, err := http.DefaultClient.Do(req); err == nil { + switch resp.StatusCode { + case 200: + json.Unmarshal([]byte(ReturnJustString(io.ReadAll(resp.Body))), &Data) + Accounttype = "Microsoft" + case 404: + Accounttype = "Giftcard" + } + } + } + return +} + +func ReturnJustString(data []byte, err error) string { + return string(data) +} + +func P_Auth(P []Payload_auth, reauth bool) { + var wg sync.WaitGroup + var Invalids []string + var invalidproxys []string + for _, acc_1 := range P { + for _, p := range acc_1.Accounts { + if acc := strings.Split(p, ":"); len(acc) > 1 { + if len(Proxy.Proxys) > 0 && Con.Bools.UseProxyDuringAuth { + wg.Add(1) + go func(proxy string, acc []string) { + ip, port, user, pass := "", "", "", "" + switch data := strings.Split(proxy, ":"); len(data) { + case 2: + ip = data[0] + port = data[1] + case 4: + ip = data[0] + port = data[1] + user = data[2] + pass = data[3] + } + var Authed bool + go func() { + for !Authed { + time.Sleep(80 * time.Second) + if !Authed { + New := Proxy.CompRand() + fmt.Println(Logo(fmt.Sprintf("<%v> %v under the ip %v has timed out, suspected dead proxy. reauthing under %v now..", time.Now().Format("05.000"), HashEmailClean(acc[0]), ip, strings.Split(New, ":")[0]))) + + invalidproxys = append(invalidproxys, fmt.Sprintf("%v:%v:%v:%v", ip, port, user, pass)) + + switch data := strings.Split(New, ":"); len(data) { + case 2: + ip = data[0] + port = data[1] + case 4: + ip = data[0] + port = data[1] + user = data[2] + pass = data[3] + } + info := apiGO.MS_authentication(acc[0], acc[1], &apiGO.ProxyMS{IP: ip, Port: port, User: user, Password: pass}) + if info.Error != "" { + Authed = true + fmt.Println(Logo(fmt.Sprintf("Account %v came up Invalid: %v", HashEmailClean(info.Email), info.Error))) + Invalids = append(Invalids, acc[0]+":"+acc[1]) + } else if info.Bearer != "" { + if IsChangeable(proxy, info.Bearer) { + Authed = true + fmt.Println(Logo(fmt.Sprintf("[%v] Succesfully authed %v", time.Now().Format("15:04:05.0000"), HashEmailClean(info.Email)))) + if reauth { + for point, bf := range Con.Bearers { + if strings.EqualFold(bf.Email, info.Email) { + Con.Bearers[point] = Bearers{ + Bearer: info.Bearer, + NameChange: true, + Type: info.AccountType, + Password: info.Password, + Email: info.Email, + AuthedAt: time.Now().Unix(), + AuthInterval: 54000, + Info: UserINFO{ + ID: info.Info.ID, + Name: info.Info.Name, + }, + } + break + } + } + for i, Bearers := range Bearer.Details { + if strings.EqualFold(Bearers.Email, info.Email) { + Bearer.Details[i] = info + break + } + } + var Found bool + E1: + for i, accs := range Accs["Giftcard"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Giftcard"][i].Accs[e] = info + Found = true + break E1 + } + } + } + if !Found { + E2: + for i, accs := range Accs["Microsoft"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Microsoft"][i].Accs[e] = info + Found = true + break E2 + } + } + } + } + } else { + Con.Bearers = append(Con.Bearers, Bearers{ + Bearer: info.Bearer, + AuthInterval: 54000, + AuthedAt: time.Now().Unix(), + Type: info.AccountType, + Email: info.Email, + Password: info.Password, + NameChange: true, + Info: UserINFO{ + ID: info.Info.ID, + Name: info.Info.Name, + }, + }) + } + } else { + fmt.Println(Logo(fmt.Sprintf("Account %v cannot name change.. %v", acc[0], info.Info.Name))) + for point, bf := range Con.Bearers { + if strings.EqualFold(bf.Email, info.Email) { + Con.Bearers[point] = Bearers{ + Type: info.AccountType, + Bearer: info.Bearer, + NameChange: false, + Password: info.Password, + Email: info.Email, + AuthedAt: time.Now().Unix(), + AuthInterval: 54000, + Info: UserINFO(info.Info), + } + break + } + } + for i, Bearers := range Bearer.Details { + if strings.EqualFold(Bearers.Email, info.Email) { + Bearer.Details[i] = info + break + } + } + var Found bool + E13: + for i, accs := range Accs["Giftcard"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Giftcard"][i].Accs[e] = info + Found = true + break E13 + } + } + } + if !Found { + E23: + for i, accs := range Accs["Microsoft"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Microsoft"][i].Accs[e] = info + Found = true + break E23 + } + } + } + } + Invalids = append(Invalids, acc[0]+":"+acc[1]) + } + } + wg.Done() + } + } + }() + info := apiGO.MS_authentication(acc[0], acc[1], &apiGO.ProxyMS{IP: ip, Port: port, User: user, Password: pass}) + if info.Error != "" { + Authed = true + fmt.Println(Logo(fmt.Sprintf("Account %v came up Invalid: %v", HashEmailClean(info.Email), info.Error))) + Invalids = append(Invalids, acc[0]+":"+acc[1]) + } else if info.Bearer != "" { + if IsChangeable(proxy, info.Bearer) { + Authed = true + fmt.Println(Logo(fmt.Sprintf("[%v] Succesfully authed %v", time.Now().Format("15:04:05.0000"), HashEmailClean(info.Email)))) + if reauth { + for point, bf := range Con.Bearers { + if strings.EqualFold(bf.Email, info.Email) { + Con.Bearers[point] = Bearers{ + Bearer: info.Bearer, + NameChange: true, + Type: info.AccountType, + Password: info.Password, + Email: info.Email, + AuthedAt: time.Now().Unix(), + AuthInterval: 54000, + Info: UserINFO{ + ID: info.Info.ID, + Name: info.Info.Name, + }, + } + break + } + } + for i, Bearers := range Bearer.Details { + if strings.EqualFold(Bearers.Email, info.Email) { + Bearer.Details[i] = info + break + } + } + var Found bool + E1: + for i, accs := range Accs["Giftcard"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Giftcard"][i].Accs[e] = info + Found = true + break E1 + } + } + } + if !Found { + E2: + for i, accs := range Accs["Microsoft"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Microsoft"][i].Accs[e] = info + Found = true + break E2 + } + } + } + } + } else { + Con.Bearers = append(Con.Bearers, Bearers{ + Bearer: info.Bearer, + AuthInterval: 54000, + AuthedAt: time.Now().Unix(), + Type: info.AccountType, + Email: info.Email, + Password: info.Password, + NameChange: true, + Info: UserINFO{ + ID: info.Info.ID, + Name: info.Info.Name, + }, + }) + } + } else { + fmt.Println(Logo(fmt.Sprintf("Account %v cannot name change.. %v", acc[0], info.Info.Name))) + for point, bf := range Con.Bearers { + if strings.EqualFold(bf.Email, info.Email) { + Con.Bearers[point] = Bearers{ + Type: info.AccountType, + Bearer: info.Bearer, + NameChange: false, + Password: info.Password, + Email: info.Email, + AuthedAt: time.Now().Unix(), + AuthInterval: 54000, + Info: UserINFO(info.Info), + } + break + } + } + for i, Bearers := range Bearer.Details { + if strings.EqualFold(Bearers.Email, info.Email) { + Bearer.Details[i] = info + break + } + } + var Found bool + E13: + for i, accs := range Accs["Giftcard"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Giftcard"][i].Accs[e] = info + Found = true + break E13 + } + } + } + if !Found { + E23: + for i, accs := range Accs["Microsoft"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Microsoft"][i].Accs[e] = info + Found = true + break E23 + } + } + } + } + Invalids = append(Invalids, acc[0]+":"+acc[1]) + } + } + wg.Done() + }(acc_1.Proxy, acc) + } else { + switch info := apiGO.MS_authentication(acc[0], acc[1], nil); true { + case info.Error != "": + fmt.Println(Logo(fmt.Sprintf("Account %v came up Invalid: %v", HashEmailClean(info.Email), info.Error))) + Invalids = append(Invalids, acc[0]+":"+acc[1]) + case info.Bearer != "" && IsChangeable("", info.Bearer): + fmt.Println(Logo(fmt.Sprintf("[%v] Succesfully authed %v", time.Now().Format("15:04:05.0000"), HashEmailClean(info.Email)))) + if reauth { + for point, bf := range Con.Bearers { + if strings.EqualFold(bf.Email, info.Email) { + Con.Bearers[point] = Bearers{ + Bearer: info.Bearer, + NameChange: true, + Type: info.AccountType, + Password: info.Password, + Email: info.Email, + AuthedAt: time.Now().Unix(), + AuthInterval: 54000, + Info: UserINFO{ + ID: info.Info.ID, + Name: info.Info.Name, + }, + } + break + } + } + for i, Bearers := range Bearer.Details { + if strings.EqualFold(Bearers.Email, info.Email) { + Bearer.Details[i] = info + break + } + } + var Found bool + E1: + for i, accs := range Accs["Giftcard"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Giftcard"][i].Accs[e] = info + Found = true + break E1 + } + } + } + if !Found { + E2: + for i, accs := range Accs["Microsoft"] { + for e, b := range accs.Accs { + if strings.EqualFold(b.Email, info.Email) { + Accs["Microsoft"][i].Accs[e] = info + Found = true + break E2 + } + } + } + } + } else { + Con.Bearers = append(Con.Bearers, Bearers{ + Bearer: info.Bearer, + AuthInterval: 54000, + AuthedAt: time.Now().Unix(), + Type: info.AccountType, + Email: info.Email, + Password: info.Password, + NameChange: true, + }) + } + default: + fmt.Println(Logo(fmt.Sprintf("Account %v Bearer is nil or it cannot name change.. [%v]", HashEmailClean(acc[0]), acc[1]))) + Invalids = append(Invalids, acc[0]+":"+acc[1]) + } + } + } + } + } + wg.Wait() + if len(Invalids) != 0 { + if _, err := os.Stat("invalids.txt"); os.IsNotExist(err) { + os.Create("invalids.txt") + } + + os.WriteFile("invalids.txt", []byte(strings.Join(Invalids, "\n")), 0644) + + scanner := bufio.NewScanner(strings.NewReader(strings.Join(Invalids, "\n"))) + for scanner.Scan() { + for i, acc := range Con.Bearers { + if strings.EqualFold(acc.Email, strings.Split(scanner.Text(), ":")[0]) { + Con.Bearers[i].NameChange = false + Con.SaveConfig() + Con.LoadState() + break + } + } + } + } + if len(invalidproxys) != 0 { + if body, err := os.ReadFile("proxys.txt"); err == nil { + strings.ReplaceAll(string(body), strings.Join(invalidproxys, "\n"), "") + fmt.Println(strings.ReplaceAll(string(body), strings.Join(invalidproxys, "\n"), "")) + } + } +} + +func IsChangeable(proxy, bearer string) bool { + data := strings.Split(proxy, ":") + var Client http.Client + switch len(data) { + case 4: + Client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{Scheme: "http", User: url.UserPassword(data[2], data[3]), Host: data[0] + ":" + data[1]})}} + case 2: + Client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: data[0] + ":" + data[1]})}} + } + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/minecraft/profile/namechange", nil) + req.Header.Add("Authorization", "Bearer "+bearer) + if resp, err := Client.Do(req); err == nil { + body, _ := io.ReadAll(resp.Body) + switch resp.StatusCode { + case 200: + var Data struct { + NC bool `json:"nameChangeAllowed"` + } + json.Unmarshal(body, &Data) + return Data.NC + case 404: + return true + } + } + return false +} + +func Regenerateallaccs() { + var use_proxy, ug int + var f bool = true + var Data []Payload_auth + for i, bearer := range Con.Bearers { + if !bearer.NOT_ENTITLED_CHECKED { + Con.Bearers[i].NOT_ENTITLED_CHECKED = true + if use_proxy >= len(Proxy.Proxys) && len(Proxy.Proxys) < len(Bearer.Details) { + break + } + + if f { + Data = append(Data, Payload_auth{Proxy: Proxy.Proxys[use_proxy]}) + f = false + use_proxy++ + } + if len(Data[ug].Accounts) != 3 { + Data[ug].Accounts = append(Data[ug].Accounts, bearer.Bearer) + } else { + ug++ + Data = append(Data, Payload_auth{Proxy: Proxy.Proxys[use_proxy], Accounts: []string{bearer.Bearer}}) + use_proxy++ + } + } + } + + for _, proxy := range Data { + go func(proxy Payload_auth) { + for _, account := range proxy.Accounts { + req, _ := http.NewRequest("GET", "https://api.minecraftservices.com/entitlements/mcstore", nil) + req.Header.Add("Authorization", "Bearer "+account) + p := strings.Split(proxy.Proxy, ":") + var P_url *url.URL + switch len(p) { + case 2: + P_url = &url.URL{ + Scheme: "http", + Host: p[0] + ":" + p[1], + } + case 4: + P_url = &url.URL{ + Scheme: "http", + Host: p[0] + ":" + p[1], + User: url.UserPassword(p[2], p[3]), + } + } + (&http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(P_url)}}).Do(req) + } + }(proxy) + } + Con.SaveConfig() + Con.LoadState() +} diff --git a/packages/utils/config.go b/packages/utils/config.go new file mode 100644 index 0000000..a985bbf --- /dev/null +++ b/packages/utils/config.go @@ -0,0 +1,101 @@ +package utils + +import ( + "encoding/json" + "io" + "main/packages/webhook" + "os" + "strings" +) + +var ( + ProxyByte = []byte(` + -- GlobalSign Root R2, valid until Dec 15, 2021 + -----BEGIN CERTIFICATE----- + MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G + A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp + Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 + MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG + A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI + hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL + v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 + eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq + tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd + C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa + zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB + mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH + V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n + bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG + 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs + J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO + 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS + ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd + AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 + TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== + -----END CERTIFICATE-----`) +) + +func (s *Config) ToJson() (Data []byte, err error) { + return json.MarshalIndent(s, "", " ") +} + +func (config *Config) SaveConfig() { + if Json, err := config.ToJson(); err == nil { + WriteFile("config.json", string(Json)) + } +} + +func (s *Config) LoadState() { + data, err := ReadFile("config.json") + if err != nil { + s.LoadFromFile() + s.Settings = AccountSettings{ + GC_ReqAmt: 1, + MFA_ReqAmt: 1, + AccountsPerGc: 5, + SleepAmtPerGc: 15000, + SleepAmtPerMfa: 10000, + Spread: 0, + UseCustomSpread: false, + } + s.Bools = Bools{ + FirstUse: true, + UseMethod: false, + UseProxyDuringAuth: false, + DownloadedPW: false, + UseWebhook: false, + } + s.SkinChange.Variant = "slim" + s.SkinChange.Link = "https://textures.minecraft.net/texture/516accb84322ca168a8cd06b4d8cc28e08b31cb0555eee01b64f9175cefe7b75" + s.Gradient = []Values{{R: "125", G: "110", B: "221"}, {R: "90%", G: "45%", B: "97%"}} + s.Webhook = webhook.Web{Embeds: []webhook.Embeds{{Description: "<@{id}> has succesfully sniped {name} with {searches} searches!", URL: "https://namemc.com/profile/{name}", Color: 5814783, Author: webhook.Author{Name: "{name}", URL: "{headurl}", IconURL: "{headurl}"}, Footer: webhook.Footer{Text: "", IconURL: ""}, Fields: []webhook.Fields{{Name: "Example", Value: "Example bio!", Inline: false}}}}} + s.SaveConfig() + return + } + + json.Unmarshal([]byte(data), s) + s.LoadFromFile() +} + +func (c *Config) LoadFromFile() { + jsonFile, err := os.Open("config.json") + if err != nil { + jsonFile, _ = os.Create("config.json") + } + + byteValue, _ := io.ReadAll(jsonFile) + json.Unmarshal(byteValue, &c) +} + +func WriteFile(path string, content string) { + os.WriteFile(path, []byte(content), 0644) +} + +func ReadFile(path string) ([]byte, error) { + return os.ReadFile(path) +} + +func HashEmailClean(email string) string { + e := strings.Split(email, "@")[0] // stfu + return e[0:2] + strings.Repeat("⋅", 2) + e[len(e)-5:] +} diff --git a/packages/utils/proxy.go b/packages/utils/proxy.go new file mode 100644 index 0000000..06f3c32 --- /dev/null +++ b/packages/utils/proxy.go @@ -0,0 +1,31 @@ +package utils + +import ( + "crypto/tls" + "encoding/base64" + "fmt" + "net" + "strings" +) + +func Connect(proxy string) (*tls.Conn, bool) { + ip := strings.Split(proxy, ":") + if conn, err := net.Dial("tcp", ip[0]+":"+ip[1]); err == nil { + if len(ip) > 2 { + conn.Write([]byte(fmt.Sprintf("CONNECT minecraftapi-bef7bxczg0amd8ef.z01.azurefd.net:443 HTTP/1.1\r\nHost: minecraftapi-bef7bxczg0amd8ef.z01.azurefd.net:443\r\nProxy-Authorization: Basic %v\r\nProxy-Connection: keep-alive\r\nUser-Agent: MCSN/1.1\r\n\r\n", base64.RawStdEncoding.EncodeToString([]byte(ip[2]+":"+ip[3]))))) + } else { + conn.Write([]byte("CONNECT minecraftapi-bef7bxczg0amd8ef.z01.azurefd.net:443 HTTP/1.1\r\nHost: minecraftapi-bef7bxczg0amd8ef.z01.azurefd.net:443\r\nProxy-Connection: keep-alive\r\nUser-Agent: MCSN/1.1\r\n\r\n")) + } + var junk = make([]byte, 4096) + conn.Read(junk) + switch Status := string(junk); Status[9:12] { + case "200": + return tls.Client(conn, &tls.Config{RootCAs: Roots, InsecureSkipVerify: true, ServerName: "minecraftapi-bef7bxczg0amd8ef.z01.azurefd.net"}), true + case "407": + fmt.Println(Logo(fmt.Sprintf("[%v] Proxy <%v> Failed to authorize: Username/Password invalid.", Status[9:12], ip[0]))) + default: + return nil, false + } + } + return nil, false +} diff --git a/packages/utils/types.go b/packages/utils/types.go new file mode 100644 index 0000000..2e61b5e --- /dev/null +++ b/packages/utils/types.go @@ -0,0 +1,166 @@ +package utils + +import ( + "crypto/x509" + "main/packages/webhook" + "time" + + "main/packages/apiGO" +) + +var ( + Roots *x509.CertPool = x509.NewCertPool() + Con Config + Proxy apiGO.Proxys + Bearer apiGO.MCbearers + RGB []string +) + +type NameMCInfo struct { + Action string `json:"action"` + Desc string `json:"desc"` + Code string `json:"code"` + Data NameMCData `json:"data"` +} +type NameMCData struct { + Status string `json:"status"` + Searches string `json:"searches"` + Begin int `json:"begin"` + End int `json:"end"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` + Headurl string `json:"headurl"` +} + +type NameMCHead struct { + Bodyurl string `json:"bodyurl"` + Headurl string `json:"headurl"` + ID string `json:"id"` +} + +type Names struct { + Name string + Taken bool +} + +type Proxies struct { + IP, Port, User, Password string +} + +type Status struct { + Data struct { + Status string `json:"status"` + } `json:"details"` +} + +type CF struct { + Tokens string `json:"tokens"` + GennedAT int64 `json:"unix_of_creation"` +} + +type Config struct { + Gradient []Values `json:"gradient"` + NMC Namemc_Data `json:"namemc_settings"` + Settings AccountSettings `json:"settings"` + Bools Bools `json:"sniper_config"` + SkinChange Skin `json:"skin_config"` + CF CF `json:"cf_tokens"` + WebhookURL string `json:"webhook_url"` + Webhook webhook.Web `json:"webhook_json"` + Bearers []Bearers `json:"Bearers"` + Recovery []Succesful `json:"recovery"` +} + +type Namemc_Data struct { + UseNMC bool `json:"usenamemc_fordroptime_andautofollow"` + Display string `json:"name_to_use_for_follows"` + Key string `json:"namemc_email:pass"` + NamemcLoginData NMC `json:"namemc_login_data"` + P []Profiles `json:"genned_profiles"` +} + +type Profiles struct { + Session_ID string `json:"session_id"` + Email string `json:"email"` + Password string `json:"password"` +} + +type NMC struct { + Token string `json:"token"` + LastAuthed int64 `json:"last_unix_auth_timestamp"` +} + +type Bearers struct { + Bearer string `json:"Bearer"` + Email string `json:"Email"` + Password string `json:"Password"` + AuthInterval int64 `json:"AuthInterval"` + AuthedAt int64 `json:"AuthedAt"` + Type string `json:"Type"` + NameChange bool `json:"NameChange"` + Info UserINFO `json:"Info"` + NOT_ENTITLED_CHECKED bool `json:"checked_entitled"` +} + +type Succesful struct { + Email string + Recovery string + Code_Used string +} +type Data struct { + Info []Succesful +} + +type Refresh struct { + Time_since_last_gen int64 `json:"last_entitled_prevention"` +} + +type AccountSettings struct { + AskForUnixPrompt bool `json:"ask_for_unix_prompt"` + AccountsPerGc int `json:"accounts_per_gc_proxy"` + GC_ReqAmt int `json:"amt_reqs_per_gc_acc"` + MFA_ReqAmt int `json:"amt_reqs_per_mfa_acc"` + SleepAmtPerGc int `json:"sleep_for_gc"` + SleepAmtPerMfa int `json:"sleep_for_mfa"` + UseCustomSpread bool `json:"use_own_spread_value"` + Spread int64 `json:"spread_ms"` +} + +type Bools struct { + UseCF bool `json:"use_cf_token"` + UseMethod bool `json:"use_method_rlbypass"` + UseProxyDuringAuth bool `json:"useproxysduringauth"` + UseWebhook bool `json:"sendpersonalwhonsnipe"` + FirstUse bool `json:"firstuse_IGNORETHIS"` + DownloadedPW bool `json:"pwinstalled_IGNORETHIS"` + ApplyNewRecoveryToExistingEmails bool `json:"applynewemailstoexistingrecoveryemails"` +} + +type Values struct { + R string `json:"r"` + G string `json:"g"` + B string `json:"b"` +} + +type Info struct { + Bearer string + RefreshToken string + AccessToken string + Expires int + AccountType string + Email string + Password string + Requests int + Info UserINFO `json:"Info"` + Error string +} + +type UserINFO struct { + ID string `json:"id"` + Name string `json:"name"` +} + +type Skin struct { + Link string `json:"url"` + Variant string `json:"variant"` +} diff --git a/packages/utils/utils.go b/packages/utils/utils.go new file mode 100644 index 0000000..eaf3cb3 --- /dev/null +++ b/packages/utils/utils.go @@ -0,0 +1,62 @@ +package utils + +import ( + "crypto/tls" + "encoding/json" + "errors" + "io" + "net/http" + "os" + "time" + + "github.com/iskaa02/qalam/gradient" +) + +func CheckForValidFile(input string) bool { + _, err := os.Stat(input) + return errors.Is(err, os.ErrNotExist) +} + +type SniperProxy struct { + Proxy *tls.Conn + UsedAt time.Time + Alive bool + ProxyDetails Proxies +} + +func IsAvailable(name string) bool { + resp, err := http.Get("https://account.mojang.com/available/minecraft/" + name) + if err == nil { + return resp.StatusCode == 200 + } else { + return false + } +} + +func Logo(Data string) string { + g, _ := gradient.NewGradientBuilder(). + HtmlColors(RGB...). + Mode(gradient.BlendRgb). + Build() + return g.Mutline(Data) +} + +func GetHeadUrl(name string) (string, string) { + if resp, err := http.Get("https://namemc.info/data/namemc/head/" + name); err == nil { + res, _ := io.ReadAll(resp.Body) + var Data NameMCHead + json.Unmarshal(res, &Data) + return Data.Headurl, Data.Bodyurl + } + return "", "" +} + +func GetDroptimes(name string) (int64, int64, string, string) { + if resp, err := http.Get("https://namemc.info/data/info/" + name); err == nil { + res, _ := io.ReadAll(resp.Body) + var Data NameMCInfo + json.Unmarshal(res, &Data) + return int64(Data.Data.Begin), int64(Data.Data.End), Data.Data.Status, Data.Data.Searches + } + return 0, 0, "", "" +} diff --git a/packages/webhook/main.go b/packages/webhook/main.go new file mode 100644 index 0000000..f187b74 --- /dev/null +++ b/packages/webhook/main.go @@ -0,0 +1,19 @@ +package webhook + +import ( + "bytes" + "errors" + "net/http" +) + +func Webhook(url string, webhook []byte) (error, bool) { + if resp, err := http.Post(url, "application/json", bytes.NewBuffer(webhook)); err != nil { + return err, false + } else { + if resp.StatusCode == 204 { + return nil, true + } else { + return errors.New("[Error] unable to send webhook " + resp.Status), false + } + } +} diff --git a/packages/webhook/types.go b/packages/webhook/types.go new file mode 100644 index 0000000..341221c --- /dev/null +++ b/packages/webhook/types.go @@ -0,0 +1,44 @@ +package webhook + +type Web struct { + Content string `json:"content"` + Embeds []Embeds `json:"embeds"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` +} + +type Embeds struct { + Description string `json:"description"` + URL string `json:"url"` + Image Image `json:"image"` + Thumbnail Thumbnail `json:"thumbnail"` + Fields []Fields `json:"fields"` + Color int `json:"color"` + Author Author `json:"author"` + Footer Footer `json:"footer"` +} + +type Fields struct { + Name string `json:"name"` + Value string `json:"value"` + Inline bool `json:"inline"` +} + +type Footer struct { + Text string `json:"text"` + IconURL string `json:"icon_url"` +} + +type Author struct { + Name string `json:"name"` + URL string `json:"url"` + IconURL string `json:"icon_url"` +} + +type Image struct { + URL string `json:"url"` +} + +type Thumbnail struct { + URL string `json:"url"` +}