├── .github └── workflows │ └── build.yml ├── .gitignore ├── Caddyfile ├── Dockerfile ├── README.md ├── cmd ├── build_cert.go ├── build_config.go ├── generate_license.go ├── root.go └── run_server.go ├── frontend ├── .gitignore ├── .npmrc ├── README.md ├── bun.lock ├── justfile ├── package.json ├── src │ ├── app.d.ts │ ├── app.html │ ├── lib │ │ ├── error.svelte │ │ ├── index.ts │ │ ├── loading.svelte │ │ └── tailwind.css │ └── routes │ │ ├── +error.svelte │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ ├── config │ │ └── [type] │ │ │ ├── +page.svelte │ │ │ └── +page.ts │ │ └── license │ │ ├── +page.svelte │ │ ├── +page.ts │ │ └── icon.svelte ├── static │ └── favicon.png ├── svelte.config.js ├── tsconfig.json └── vite.config.ts ├── go.mod ├── go.sum ├── internal ├── algo │ └── rsa.go ├── cert │ └── cert.go ├── config │ └── config.go ├── license │ ├── code.go │ └── license.go └── util │ └── random.go ├── justfile ├── main.go └── server ├── config └── config.go ├── handler ├── base.go ├── config.go ├── license.go ├── obtain_ticket.go ├── ping.go └── release_ticket.go ├── middleware ├── certificate.go └── middleware.go ├── router └── router.go └── server.go /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Multi-Platform Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | - 'master' 8 | 9 | jobs: 10 | build: 11 | name: Build for ${{ matrix.os }} 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, windows-latest, macos-latest] 16 | include: 17 | - os: ubuntu-latest 18 | platform: linux 19 | binary_name: jetbrain-hacker_${{ github.ref_name }}_linux_amd64 20 | - os: windows-latest 21 | platform: windows 22 | binary_name: jetbrain-hacker_${{ github.ref_name }}_windows_amd64.exe 23 | - os: macos-latest 24 | platform: macos 25 | binary_name: jetbrain-hacker_${{ github.ref_name }}_darwin_amd64 26 | 27 | steps: 28 | - name: Checkout code 29 | uses: actions/checkout@v4 30 | 31 | - name: Set up Go 32 | uses: actions/setup-go@v4 33 | with: 34 | go-version: '1.24' 35 | 36 | - name: Init Go 37 | run: go mod tidy 38 | 39 | - name: Build 40 | run: go build -v -o ${{ matrix.binary_name }} . 41 | 42 | - name: Upload Artifact 43 | uses: actions/upload-artifact@v4.6.2 44 | with: 45 | name: ${{ matrix.binary_name }} 46 | path: ${{ matrix.binary_name }} 47 | 48 | - name: Release 49 | uses: softprops/action-gh-release@v2 50 | if: github.ref_type == 'tag' 51 | with: 52 | files: ${{ matrix.binary_name }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ -------------------------------------------------------------------------------- /Caddyfile: -------------------------------------------------------------------------------- 1 | { 2 | auto_https disable_certs 3 | } 4 | 5 | :80 { 6 | encode gzip 7 | handle_path /api/* { 8 | reverse_proxy localhost:8080 9 | } 10 | handle /rpc/* { 11 | reverse_proxy localhost:8080 12 | } 13 | reverse_proxy localhost:3000 14 | log { 15 | output file /var/log/caddy/caddy.log 16 | } 17 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest 2 | LABEL authors="LovesAsuna" 3 | 4 | WORKDIR /usr/src/jetbrains_hacker 5 | 6 | COPY . . 7 | 8 | RUN apt-get update \ 9 | && apt-get install -y wget curl unzip 10 | 11 | RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin 12 | CMD ["just"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Cover](https://capsule-render.vercel.app/api?type=waving&height=300&color=gradient&text=JetBrains%20Hacker&desc=Build%20your%20own%20license!&descAlignY=60&descAlign=70) 2 | 3 | --- 4 | 5 | # JetBrains Hacker 6 | 7 | JetBrains Hacker is a tool that can customize your JetBrains IDEs license. 8 | 9 | I create it to activate my common IDEs, and hope that it can be useful to others. 10 | 11 | ## Features 12 | 13 | - 💪 Useful - Offline activation code and online license server. 14 | - 🔨 Customize - Any information as you want, just make your own license. 15 | 16 | ## Usage 17 | 18 | 1. Get the `ja-netfilter` from the Internet. This software is worked based on the `ja-netfilter`. 19 | 20 | 2. Add -javaagent:/path/to/ja-netfilter.jar=`${app}` to your vmoptions (manual or auto). Note that `${app}` is a parameter to `ja-netfilter` that specifies the location of the `config-${app}` and `plugins-${app}` folders, if empty the `config` and `plugins` folders will be used by default. 21 | 22 | 23 | > for Java version 17+, you need add these 2 lines to your vmoptions file: (for manual, without any whitespace chars) 24 | 25 | ```vmoptions 26 | --add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED 27 | --add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED 28 | ``` 29 | 30 | 3. Get the `jetbrains hacker`. See [Installation](#installation) or [Build](#build) on bellowed. 31 | 32 | 4. There are two ways to use the `jetbrains hacker`. 33 | 34 | ### Activation Code 35 | 36 | > This approach is used in offline scenario. 37 | 38 | 1. Run `jetbrains_hacker build-cert` to build needed certificates. 39 | 2. Run `jetbrains_hacker build-config --type {power|url|dns}` to generate the corresponding configurations. Then copy the generated configurations into your `ja-netfilter` configuration files. 40 | 3. Run `jetbrains_hacker generate-license --licenseId ${licenseId} --name ${name} --user ${user} --email ${email} --time {2999-01-02}`. Or simplest of all, you can just use `jetbrain_hacker generate-license`. 41 | 4. Use the activation code in the `Activation Code` window. 42 | 5. Don't care about the activation time, it is a fallback license and will not expire. 43 | 44 | Enjoy it~ 45 | 46 | ### License Server 47 | 48 | > This approach is used in online scenario. 49 | 50 | 1. Run `jetbrains_hacker run-server` to run a online license server. By default the server will run on `:80`. If you want to change the address, use the `--addr` argument. 51 | 2. Go to `${your server address}/config/{power|url|dns}` to get the corresponding configurations. Then copy the generated configurations into your `ja-netfilter` configuration files. 52 | 3. Type your server address in the `License Server` window. 53 | 4. Don't care about the activation time, it is a fallback license and will not expire. 54 | 55 | Enjoy it~ 56 | 57 | ## Installation 58 | 59 | You can choose to use the pre-compiled binary or build it by yourself. 60 | 61 | ### Release Binaries 62 | 63 | [Available for download in releases](https://github.com/LovesAsuna/jetbrains_hacker/releases) 64 | 65 | Binaries available for: 66 | 67 | #### Linux 68 | 69 | - jetbrain-hacker_linux_amd64 (linux musl statically linked) 70 | - jetbrains_hacker-linux-aarch64.tar.gz (linux on 64 bit arm) 71 | 72 | All contain a single binary file 73 | 74 | #### macOS 75 | 76 | - jetbrains_hacker-mac.tar.gz (arm64) 77 | - jetbrain-hacker_darwin_amd64 (intel x86) 78 | 79 | #### Windows 80 | 81 | - jetbrain-hacker_windows_amd64.exe (single 64bit binary) 82 | 83 | ## Build 84 | 85 | ### Requirements 86 | 87 | - Minimum supported `go` version: `1.24` 88 | - See [Install Go](https://go.dev/dl/) 89 | 90 | - To build needed dependency (run `go mod tidy`) 91 | 92 | ### Go Install 93 | 94 | The simplest way to start playing around with `jetbrains_hacker` is to have `go` build and install it with `go build .`. 95 | -------------------------------------------------------------------------------- /cmd/build_cert.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var buildCertCmd = &cobra.Command{ 10 | Use: "build-cert", 11 | Short: `Build all needed certificates.`, 12 | Long: `Build all needed certificates included user certificate and license server certificate.`, 13 | RunE: func(cmd *cobra.Command, args []string) error { 14 | if _, err := cert.GenerateFakeCertificate( 15 | cert.JetProfileCert.CommonName(), 16 | cmd.Flag("user-cert-cn").Value.String(), 17 | cmd.Flag("user-cert").Value.String(), 18 | cmd.Flag("user-key").Value.String(), 19 | ); err != nil { 20 | return err 21 | } 22 | if _, err := cert.GenerateFakeCertificate( 23 | cert.LicenseServerCert.CommonName(), 24 | fmt.Sprintf("%s.lsrv.jetbrains.com", cmd.Flag("server-uid").Value.String()), 25 | cmd.Flag("license-server-cert").Value.String(), 26 | cmd.Flag("license-server-key").Value.String(), 27 | ); err != nil { 28 | return err 29 | } 30 | fmt.Println("build cert successfully!") 31 | return nil 32 | }, 33 | } 34 | 35 | func init() { 36 | rootCmd.AddCommand(buildCertCmd) 37 | 38 | buildCertCmd.Flags().StringP("user-cert-cn", "n", "localhost", "Common name of the user certificate.") 39 | buildCertCmd.Flags().StringP("server-uid", "s", "custom", "The server uid of license server.") 40 | } 41 | -------------------------------------------------------------------------------- /cmd/build_config.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 6 | "github.com/LovesAsuna/jetbrains_hacker/internal/config" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var buildConfigCmd = &cobra.Command{ 11 | Use: "build-config", 12 | Short: `Build the *.conf of ja-netfilter.`, 13 | Long: `Build the *.conf of ja-netfilter.`, 14 | RunE: func(cmd *cobra.Command, args []string) error { 15 | switch cmd.Flag("type").Value.String() { 16 | case "dns": 17 | fmt.Println(config.BuildDnsConfig()) 18 | return nil 19 | case "url": 20 | fmt.Println(config.BuildUrlConfig()) 21 | return nil 22 | case "power": 23 | userCert, err := cert.CreateCertFromFileWithoutPrivateKey(cmd.Flag("user-cert").Value.String()) 24 | if err != nil { 25 | return err 26 | } 27 | licenseServerCert, err := cert.CreateCertFromFileWithoutPrivateKey(cmd.Flag("license-server-cert").Value.String()) 28 | if err != nil { 29 | return err 30 | } 31 | fmt.Println( 32 | config.BuildPowerConfig( 33 | [2]*cert.Certificate{ 34 | userCert, cert.JetProfileCert, 35 | }, 36 | [2]*cert.Certificate{ 37 | licenseServerCert, cert.LicenseServerCert, 38 | }, 39 | ), 40 | ) 41 | default: 42 | fmt.Println("unknown config type.") 43 | } 44 | return nil 45 | }, 46 | } 47 | 48 | func init() { 49 | rootCmd.AddCommand(buildConfigCmd) 50 | 51 | buildConfigCmd.Flags().StringP("type", "t", "power", "If empty use power. Possible values: 'power', 'dns', 'url'.") 52 | } 53 | -------------------------------------------------------------------------------- /cmd/generate_license.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 8 | "github.com/LovesAsuna/jetbrains_hacker/internal/license" 9 | "github.com/LovesAsuna/jetbrains_hacker/internal/util" 10 | "github.com/dromara/carbon/v2" 11 | "github.com/lovesasuna/sync/coroutinegroup" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | var generateLicenseCmd = &cobra.Command{ 16 | Use: "generate-license", 17 | Short: `generate-license.`, 18 | Long: `generate-license.`, 19 | RunE: func(cmd *cobra.Command, args []string) error { 20 | licenseId := cmd.Flag("licenseId").Value.String() 21 | codes, err := getCodes() 22 | if err != nil { 23 | return err 24 | } 25 | licenseCode, err := license.GenerateLicenseCode( 26 | cert.MustCreateCertFromFile(cmd.Flag("user-cert").Value.String(), cmd.Flag("user-key").Value.String()), 27 | licenseId, 28 | cmd.Flag("name").Value.String(), 29 | cmd.Flag("user").Value.String(), 30 | cmd.Flag("email").Value.String(), 31 | cmd.Flag("time").Value.String(), 32 | codes..., 33 | ) 34 | if err != nil { 35 | return err 36 | } 37 | fmt.Println(licenseCode) 38 | return nil 39 | }, 40 | } 41 | 42 | func getCodes() ([]string, error) { 43 | var ( 44 | productCodes []string 45 | pluginCodes []string 46 | ) 47 | group, _ := coroutinegroup.WithContext(context.Background()) 48 | group.Go( 49 | func(ctx context.Context) error { 50 | codes, err := license.GetProductCode() 51 | if err != nil { 52 | return err 53 | } 54 | productCodes = codes 55 | return nil 56 | }, 57 | ) 58 | group.Go( 59 | func(ctx context.Context) error { 60 | codes, err := license.GetPluginCode(10000, 0, "") 61 | if err != nil { 62 | return err 63 | } 64 | pluginCodes = codes 65 | return nil 66 | }, 67 | ) 68 | errs := group.Wait() 69 | if len(errs) > 0 { 70 | return nil, errors.Join(errs...) 71 | } 72 | codes := make([]string, 0, len(productCodes)+len(pluginCodes)) 73 | codes = append(codes, productCodes...) 74 | codes = append(codes, pluginCodes...) 75 | return codes, nil 76 | } 77 | 78 | func init() { 79 | rootCmd.AddCommand(generateLicenseCmd) 80 | 81 | generateLicenseCmd.Flags().String("licenseId", util.GetRandomString(10), "Id of license.") 82 | generateLicenseCmd.Flags().String("name", "user", "The licensee name of license.") 83 | generateLicenseCmd.Flags().String("user", "user", "The assignee name of license.") 84 | generateLicenseCmd.Flags().String("email", "i@user.com", "The assignee email of license.") 85 | generateLicenseCmd.Flags().String("time", carbon.Now().AddYears(2).SetLayout(carbon.DateLayout).String(), "The expire time of license.") 86 | } 87 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "os" 6 | ) 7 | 8 | // rootCmd represents the base command when called without any subcommands. 9 | var rootCmd = &cobra.Command{ 10 | Use: "jetbrain-hacker", 11 | Short: "Generate custom license code or run a license server.", 12 | Long: `Generate custom license code or run a license server.`, 13 | } 14 | 15 | // Execute adds all child commands to the root command and sets flags appropriately. 16 | // This is called by main.main(). It only needs to happen once to the rootCmd. 17 | func Execute() { 18 | if err := rootCmd.Execute(); err != nil { 19 | os.Exit(1) 20 | } 21 | } 22 | 23 | func init() { 24 | rootCmd.PersistentFlags().StringP("user-cert", "c", "cert/user.crt", "Path to store the user certificate.") 25 | rootCmd.PersistentFlags().StringP("user-key", "k", "cert/user.key", "Path to store the user private key.") 26 | rootCmd.PersistentFlags().String("license-server-cert", "cert/license_server.crt", "Path to store the license server certificate.") 27 | rootCmd.PersistentFlags().String("license-server-key", "cert/license_server.key", "Path to store the license server private key.") 28 | } 29 | -------------------------------------------------------------------------------- /cmd/run_server.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/server" 5 | "github.com/LovesAsuna/jetbrains_hacker/server/config" 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var runServerCmd = &cobra.Command{ 10 | Use: "run-server", 11 | Short: `Run a JetBrain license server.`, 12 | Long: `Run a JetBrain license server.`, 13 | RunE: func(cmd *cobra.Command, args []string) error { 14 | config.InitServerConfig( 15 | &config.ServerConfig{ 16 | Addr: cmd.Flag("addr").Value.String(), 17 | Licensee: cmd.Flag("licensee").Value.String(), 18 | UserCertPath: cmd.Flag("user-cert").Value.String(), 19 | UserPrivateKeyPath: cmd.Flag("user-key").Value.String(), 20 | LicenseServerCertPath: cmd.Flag("license-server-cert").Value.String(), 21 | LicenseServerPrivateKeyPath: cmd.Flag("license-server-key").Value.String(), 22 | }, 23 | ) 24 | return server.RunServer() 25 | }, 26 | } 27 | 28 | func init() { 29 | rootCmd.AddCommand(runServerCmd) 30 | 31 | runServerCmd.Flags().String("addr", ":80", "The address of license server.") 32 | runServerCmd.Flags().String("licensee", "", "The licensee of license server. Default to computer user name") 33 | } 34 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | .netlify 7 | .wrangler 8 | /.svelte-kit 9 | /build 10 | 11 | # OS 12 | .DS_Store 13 | Thumbs.db 14 | 15 | # Env 16 | .env 17 | .env.* 18 | !.env.example 19 | !.env.test 20 | 21 | # Vite 22 | vite.config.js.timestamp-* 23 | vite.config.ts.timestamp-* 24 | 25 | *.iml 26 | .idea/ -------------------------------------------------------------------------------- /frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # sv 2 | 3 | Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npx sv create 12 | 13 | # create a new project in my-app 14 | npx sv create my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /frontend/bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "frontend", 6 | "devDependencies": { 7 | "@sveltejs/adapter-auto": "^6.0.0", 8 | "@sveltejs/adapter-node": "^5.2.12", 9 | "@sveltejs/adapter-static": "^3.0.8", 10 | "@sveltejs/kit": "^2.16.0", 11 | "@sveltejs/vite-plugin-svelte": "^5.0.0", 12 | "@tailwindcss/vite": "^4.1.6", 13 | "svelte": "^5.0.0", 14 | "svelte-check": "^4.0.0", 15 | "tailwindcss": "^4.1.6", 16 | "typescript": "^5.0.0", 17 | "vite": "^6.3.5", 18 | }, 19 | }, 20 | }, 21 | "packages": { 22 | "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], 23 | 24 | "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ=="], 25 | 26 | "@esbuild/android-arm": ["@esbuild/android-arm@0.25.3", "", { "os": "android", "cpu": "arm" }, "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A=="], 27 | 28 | "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.3", "", { "os": "android", "cpu": "arm64" }, "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ=="], 29 | 30 | "@esbuild/android-x64": ["@esbuild/android-x64@0.25.3", "", { "os": "android", "cpu": "x64" }, "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ=="], 31 | 32 | "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w=="], 33 | 34 | "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A=="], 35 | 36 | "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw=="], 37 | 38 | "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q=="], 39 | 40 | "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.3", "", { "os": "linux", "cpu": "arm" }, "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ=="], 41 | 42 | "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A=="], 43 | 44 | "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw=="], 45 | 46 | "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g=="], 47 | 48 | "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag=="], 49 | 50 | "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg=="], 51 | 52 | "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA=="], 53 | 54 | "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ=="], 55 | 56 | "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.3", "", { "os": "linux", "cpu": "x64" }, "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA=="], 57 | 58 | "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.3", "", { "os": "none", "cpu": "arm64" }, "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA=="], 59 | 60 | "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.3", "", { "os": "none", "cpu": "x64" }, "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g=="], 61 | 62 | "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ=="], 63 | 64 | "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w=="], 65 | 66 | "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA=="], 67 | 68 | "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ=="], 69 | 70 | "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew=="], 71 | 72 | "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.3", "", { "os": "win32", "cpu": "x64" }, "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg=="], 73 | 74 | "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], 75 | 76 | "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], 77 | 78 | "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 79 | 80 | "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], 81 | 82 | "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 83 | 84 | "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 85 | 86 | "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], 87 | 88 | "@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@28.0.3", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ=="], 89 | 90 | "@rollup/plugin-json": ["@rollup/plugin-json@6.1.0", "", { "dependencies": { "@rollup/pluginutils": "^5.1.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA=="], 91 | 92 | "@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA=="], 93 | 94 | "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], 95 | 96 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.1", "", { "os": "android", "cpu": "arm" }, "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw=="], 97 | 98 | "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.1", "", { "os": "android", "cpu": "arm64" }, "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw=="], 99 | 100 | "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.40.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA=="], 101 | 102 | "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.40.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw=="], 103 | 104 | "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.40.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw=="], 105 | 106 | "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.40.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q=="], 107 | 108 | "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.40.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg=="], 109 | 110 | "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.40.1", "", { "os": "linux", "cpu": "arm" }, "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg=="], 111 | 112 | "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.40.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg=="], 113 | 114 | "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.40.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ=="], 115 | 116 | "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ=="], 117 | 118 | "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.40.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg=="], 119 | 120 | "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ=="], 121 | 122 | "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA=="], 123 | 124 | "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.40.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg=="], 125 | 126 | "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.40.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ=="], 127 | 128 | "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.40.1", "", { "os": "linux", "cpu": "x64" }, "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ=="], 129 | 130 | "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.40.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg=="], 131 | 132 | "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.40.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA=="], 133 | 134 | "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA=="], 135 | 136 | "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], 137 | 138 | "@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@6.0.0", "", { "dependencies": { "import-meta-resolve": "^4.1.0" }, "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-7mR2/G7vlXakaOj6QBSG9dwBfTgWjV+UnEMB5Z6Xu0ZbdXda6c0su1fNkg0ab0zlilSkloMA2NjCna02/DR7sA=="], 139 | 140 | "@sveltejs/adapter-node": ["@sveltejs/adapter-node@5.2.12", "", { "dependencies": { "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "rollup": "^4.9.5" }, "peerDependencies": { "@sveltejs/kit": "^2.4.0" } }, "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ=="], 141 | 142 | "@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.8", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg=="], 143 | 144 | "@sveltejs/kit": ["@sveltejs/kit@2.20.8", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-ep9qTxL7WALhfm0kFecL3VHeuNew8IccbYGqv5TqL/KSqWRKzEgDG8blNlIu1CkLTTua/kHjI+f5T8eCmWIxKw=="], 145 | 146 | "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.0.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.15", "vitefu": "^1.0.4" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw=="], 147 | 148 | "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], 149 | 150 | "@tailwindcss/node": ["@tailwindcss/node@4.1.6", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.6" } }, "sha512-ed6zQbgmKsjsVvodAS1q1Ld2BolEuxJOSyyNc+vhkjdmfNUDCmQnlXBfQkHrlzNmslxHsQU/bFmzcEbv4xXsLg=="], 151 | 152 | "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.6", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.6", "@tailwindcss/oxide-darwin-arm64": "4.1.6", "@tailwindcss/oxide-darwin-x64": "4.1.6", "@tailwindcss/oxide-freebsd-x64": "4.1.6", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.6", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.6", "@tailwindcss/oxide-linux-arm64-musl": "4.1.6", "@tailwindcss/oxide-linux-x64-gnu": "4.1.6", "@tailwindcss/oxide-linux-x64-musl": "4.1.6", "@tailwindcss/oxide-wasm32-wasi": "4.1.6", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.6", "@tailwindcss/oxide-win32-x64-msvc": "4.1.6" } }, "sha512-0bpEBQiGx+227fW4G0fLQ8vuvyy5rsB1YIYNapTq3aRsJ9taF3f5cCaovDjN5pUGKKzcpMrZst/mhNaKAPOHOA=="], 153 | 154 | "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.6", "", { "os": "android", "cpu": "arm64" }, "sha512-VHwwPiwXtdIvOvqT/0/FLH/pizTVu78FOnI9jQo64kSAikFSZT7K4pjyzoDpSMaveJTGyAKvDjuhxJxKfmvjiQ=="], 155 | 156 | "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-weINOCcqv1HVBIGptNrk7c6lWgSFFiQMcCpKM4tnVi5x8OY2v1FrV76jwLukfT6pL1hyajc06tyVmZFYXoxvhQ=="], 157 | 158 | "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3FzekhHG0ww1zQjQ1lPoq0wPrAIVXAbUkWdWM8u5BnYFZgb9ja5ejBqyTgjpo5mfy0hFOoMnMuVDI+7CXhXZaQ=="], 159 | 160 | "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4m5F5lpkBZhVQJq53oe5XgJ+aFYWdrgkMwViHjRsES3KEu2m1udR21B1I77RUqie0ZYNscFzY1v9aDssMBZ/1w=="], 161 | 162 | "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.6", "", { "os": "linux", "cpu": "arm" }, "sha512-qU0rHnA9P/ZoaDKouU1oGPxPWzDKtIfX7eOGi5jOWJKdxieUJdVV+CxWZOpDWlYTd4N3sFQvcnVLJWJ1cLP5TA=="], 163 | 164 | "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-jXy3TSTrbfgyd3UxPQeXC3wm8DAgmigzar99Km9Sf6L2OFfn/k+u3VqmpgHQw5QNfCpPe43em6Q7V76Wx7ogIQ=="], 165 | 166 | "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-8kjivE5xW0qAQ9HX9reVFmZj3t+VmljDLVRJpVBEoTR+3bKMnvC7iLcoSGNIUJGOZy1mLVq7x/gerVg0T+IsYw=="], 167 | 168 | "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-A4spQhwnWVpjWDLXnOW9PSinO2PTKJQNRmL/aIl2U/O+RARls8doDfs6R41+DAXK0ccacvRyDpR46aVQJJCoCg=="], 169 | 170 | "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-YRee+6ZqdzgiQAHVSLfl3RYmqeeaWVCk796MhXhLQu2kJu2COHBkqlqsqKYx3p8Hmk5pGCQd2jTAoMWWFeyG2A=="], 171 | 172 | "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.6", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.9", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-qAp4ooTYrBQ5pk5jgg54/U1rCJ/9FLYOkkQ/nTE+bVMseMfB6O7J8zb19YTpWuu4UdfRf5zzOrNKfl6T64MNrQ=="], 173 | 174 | "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-nqpDWk0Xr8ELO/nfRUDjk1pc9wDJ3ObeDdNMHLaymc4PJBWj11gdPCWZFKSK2AVKjJQC7J2EfmSmf47GN7OuLg=="], 175 | 176 | "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-5k9xF33xkfKpo9wCvYcegQ21VwIBU1/qEbYlVukfEIyQbEA47uK8AAwS7NVjNE3vHzcmxMYwd0l6L4pPjjm1rQ=="], 177 | 178 | "@tailwindcss/vite": ["@tailwindcss/vite@4.1.6", "", { "dependencies": { "@tailwindcss/node": "4.1.6", "@tailwindcss/oxide": "4.1.6", "tailwindcss": "4.1.6" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-zjtqjDeY1w3g2beYQtrMAf51n5G7o+UwmyOjtsDMP7t6XyoRMOidcoKP32ps7AkNOHIXEOK0bhIC05dj8oJp4w=="], 179 | 180 | "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], 181 | 182 | "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], 183 | 184 | "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], 185 | 186 | "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], 187 | 188 | "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], 189 | 190 | "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], 191 | 192 | "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 193 | 194 | "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], 195 | 196 | "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], 197 | 198 | "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], 199 | 200 | "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], 201 | 202 | "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 203 | 204 | "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], 205 | 206 | "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], 207 | 208 | "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], 209 | 210 | "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], 211 | 212 | "esbuild": ["esbuild@0.25.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.3", "@esbuild/android-arm": "0.25.3", "@esbuild/android-arm64": "0.25.3", "@esbuild/android-x64": "0.25.3", "@esbuild/darwin-arm64": "0.25.3", "@esbuild/darwin-x64": "0.25.3", "@esbuild/freebsd-arm64": "0.25.3", "@esbuild/freebsd-x64": "0.25.3", "@esbuild/linux-arm": "0.25.3", "@esbuild/linux-arm64": "0.25.3", "@esbuild/linux-ia32": "0.25.3", "@esbuild/linux-loong64": "0.25.3", "@esbuild/linux-mips64el": "0.25.3", "@esbuild/linux-ppc64": "0.25.3", "@esbuild/linux-riscv64": "0.25.3", "@esbuild/linux-s390x": "0.25.3", "@esbuild/linux-x64": "0.25.3", "@esbuild/netbsd-arm64": "0.25.3", "@esbuild/netbsd-x64": "0.25.3", "@esbuild/openbsd-arm64": "0.25.3", "@esbuild/openbsd-x64": "0.25.3", "@esbuild/sunos-x64": "0.25.3", "@esbuild/win32-arm64": "0.25.3", "@esbuild/win32-ia32": "0.25.3", "@esbuild/win32-x64": "0.25.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q=="], 213 | 214 | "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], 215 | 216 | "esrap": ["esrap@1.4.6", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw=="], 217 | 218 | "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], 219 | 220 | "fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="], 221 | 222 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 223 | 224 | "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 225 | 226 | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], 227 | 228 | "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 229 | 230 | "import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="], 231 | 232 | "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], 233 | 234 | "is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="], 235 | 236 | "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], 237 | 238 | "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], 239 | 240 | "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], 241 | 242 | "lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="], 243 | 244 | "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="], 245 | 246 | "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="], 247 | 248 | "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="], 249 | 250 | "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="], 251 | 252 | "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="], 253 | 254 | "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="], 255 | 256 | "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="], 257 | 258 | "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="], 259 | 260 | "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="], 261 | 262 | "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="], 263 | 264 | "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], 265 | 266 | "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], 267 | 268 | "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], 269 | 270 | "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], 271 | 272 | "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], 273 | 274 | "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], 275 | 276 | "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], 277 | 278 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 279 | 280 | "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 281 | 282 | "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], 283 | 284 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 285 | 286 | "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], 287 | 288 | "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], 289 | 290 | "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 291 | 292 | "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], 293 | 294 | "rollup": ["rollup@4.40.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.1", "@rollup/rollup-android-arm64": "4.40.1", "@rollup/rollup-darwin-arm64": "4.40.1", "@rollup/rollup-darwin-x64": "4.40.1", "@rollup/rollup-freebsd-arm64": "4.40.1", "@rollup/rollup-freebsd-x64": "4.40.1", "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", "@rollup/rollup-linux-arm-musleabihf": "4.40.1", "@rollup/rollup-linux-arm64-gnu": "4.40.1", "@rollup/rollup-linux-arm64-musl": "4.40.1", "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", "@rollup/rollup-linux-riscv64-gnu": "4.40.1", "@rollup/rollup-linux-riscv64-musl": "4.40.1", "@rollup/rollup-linux-s390x-gnu": "4.40.1", "@rollup/rollup-linux-x64-gnu": "4.40.1", "@rollup/rollup-linux-x64-musl": "4.40.1", "@rollup/rollup-win32-arm64-msvc": "4.40.1", "@rollup/rollup-win32-ia32-msvc": "4.40.1", "@rollup/rollup-win32-x64-msvc": "4.40.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw=="], 295 | 296 | "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], 297 | 298 | "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], 299 | 300 | "sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="], 301 | 302 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 303 | 304 | "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], 305 | 306 | "svelte": ["svelte@5.28.2", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^1.4.6", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-FbWBxgWOpQfhKvoGJv/TFwzqb4EhJbwCD17dB0tEpQiw1XyUEKZJtgm4nA4xq3LLsMo7hu5UY/BOFmroAxKTMg=="], 307 | 308 | "svelte-check": ["svelte-check@4.1.7", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-1jX4BzXrQJhC/Jt3SqYf6Ntu//vmfc6VWp07JkRfK2nn+22yIblspVUo96gzMkg0Zov8lQicxhxsMzOctwcMQQ=="], 309 | 310 | "tailwindcss": ["tailwindcss@4.1.6", "", {}, "sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg=="], 311 | 312 | "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], 313 | 314 | "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], 315 | 316 | "tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="], 317 | 318 | "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], 319 | 320 | "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], 321 | 322 | "vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], 323 | 324 | "vitefu": ["vitefu@1.0.6", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA=="], 325 | 326 | "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], 327 | 328 | "zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="], 329 | 330 | "@rollup/plugin-commonjs/is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="], 331 | 332 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], 333 | 334 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], 335 | 336 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], 337 | 338 | "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.9", "", { "dependencies": { "@emnapi/core": "^1.4.0", "@emnapi/runtime": "^1.4.0", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg=="], 339 | 340 | "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], 341 | 342 | "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /frontend/justfile: -------------------------------------------------------------------------------- 1 | frontend: build_frontend 2 | #!/bin/env bash 3 | source ~/.bashrc 4 | bun run build/ & 5 | 6 | build_frontend: bun 7 | #!/bin/env bash 8 | source ~/.bashrc 9 | bun install 10 | bun run build 11 | 12 | bun: 13 | #!/bin/env bash 14 | curl -fsSL https://bun.sh/install | bash 15 | source ~/.bashrc -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite dev", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "prepare": "svelte-kit sync || echo ''", 11 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" 13 | }, 14 | "devDependencies": { 15 | "@sveltejs/adapter-auto": "^6.0.0", 16 | "@sveltejs/kit": "^2.16.0", 17 | "@sveltejs/vite-plugin-svelte": "^5.0.0", 18 | "svelte": "^5.0.0", 19 | "svelte-check": "^4.0.0", 20 | "typescript": "^5.0.0", 21 | "vite": "^6.3.5", 22 | "@sveltejs/adapter-node": "^5.2.12", 23 | "@sveltejs/adapter-static": "^3.0.8", 24 | "@tailwindcss/vite": "^4.1.6", 25 | "tailwindcss": "^4.1.6" 26 | } 27 | } -------------------------------------------------------------------------------- /frontend/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://svelte.dev/docs/kit/types#app.d.ts 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /frontend/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/lib/error.svelte: -------------------------------------------------------------------------------- 1 | 2 |
3 | 14 |

Error 404

15 |

The page you're looking for can't be found

16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /frontend/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /frontend/src/lib/loading.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Loading data...

5 |
6 | 7 | -------------------------------------------------------------------------------- /frontend/src/lib/tailwind.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; -------------------------------------------------------------------------------- /frontend/src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {@render children()} 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | JetBrains_Hacker 5 |

6 |

7 | This is a 8 | 9 | JetBrains 10 | 11 | license server. 12 |

13 |

It provides a license server for JetBrains IDEs.

14 |

Documentation:

15 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /frontend/src/routes/config/[type]/+page.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | {#await data.loader()} 18 | 19 | {:then c } 20 | 21 | 22 | {:catch _} 23 | 24 | {/await} 25 | 26 | -------------------------------------------------------------------------------- /frontend/src/routes/config/[type]/+page.ts: -------------------------------------------------------------------------------- 1 | import type {PageLoad} from './$types'; 2 | 3 | export type Config = { 4 | type: string; 5 | config: string; 6 | } 7 | 8 | export const load: PageLoad = ({params, fetch}) => { 9 | return { 10 | loader: async function() { 11 | let response = await fetch(`/api/config/${params.type}`); 12 | let text = await response.text(); 13 | return JSON.parse(text); 14 | } 15 | } 16 | }; -------------------------------------------------------------------------------- /frontend/src/routes/license/+page.svelte: -------------------------------------------------------------------------------- 1 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |

45 | Download jetbra.zip, and configure as described in 49 | readme.txt! For testing purposes only, not for 50 | commercial use!
51 | Please note that this is just a personal page, not an official website! 52 |

53 |
54 | 55 |
57 | {#each productList as product} 58 |
61 |
62 |
63 |
64 | 66 | 67 | 68 |
69 | 80 |
81 |
82 |
83 |
84 |

{product.name}

86 |

{copyLicense(event, product.code)}} 91 | data-content="Copy to clipboard"> 92 | ********************************************************************************************************************************************************* 93 |

94 |
95 |
96 |
97 |
98 | {/each} 99 |
100 |
101 |
102 | All the above keys are collected from the Internet and are for testing purposes only, not for commercial use! 103 |
104 |
Theme by QieTuZai
105 |
106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /frontend/src/routes/license/+page.ts: -------------------------------------------------------------------------------- 1 | import type {PageLoad} from './$types'; 2 | 3 | export interface ProductDto { 4 | code: string, 5 | salesCode: string, 6 | name: string, 7 | description: string, 8 | forSale: boolean 9 | productFamilyName: string 10 | releases: Array<{ version: string }> 11 | } 12 | 13 | export interface Product { 14 | code: string, 15 | name: string, 16 | productFamilyName: string 17 | version: string 18 | } 19 | 20 | const DataBaseUrl = "https://data.services.jetbrains.com" 21 | export const load: PageLoad = async ({fetch}) => { 22 | let resp = await fetch(`${DataBaseUrl}/products?fields=name,code,forSale,salesCode,description,productFamilyName,releases.version`) 23 | let productDtos: Array = await resp.json() 24 | let products: Array = []; 25 | productDtos.forEach(dto => { 26 | dto.productFamilyName = dto.productFamilyName.replace(" ", "-").toLowerCase() 27 | let extra = dto.forSale && (dto.salesCode != dto.code); 28 | products.push( 29 | { 30 | code: dto.code, 31 | name: extra ? `${dto.name}(${dto.code})` : dto.name, 32 | productFamilyName: dto.productFamilyName, 33 | version: dto.releases.length > 0 ? dto.releases[0].version: "" 34 | } 35 | ); 36 | if (extra) { 37 | products.push( 38 | { 39 | code: dto.salesCode, 40 | name: `${dto.name}(${dto.salesCode})`, 41 | productFamilyName: dto.productFamilyName, 42 | version: dto.releases.length > 0 ? dto.releases[0].version: "" 43 | } 44 | ); 45 | } 46 | }); 47 | return { 48 | products 49 | } 50 | }; -------------------------------------------------------------------------------- /frontend/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LovesAsuna/jetbrains_hacker/c71a12145d44132dc93987ba7993ec048ef8a13d/frontend/static/favicon.png -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-node'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://svelte.dev/docs/kit/integrations 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. 12 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 13 | // See https://svelte.dev/docs/kit/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias 15 | // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files 16 | // 17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 18 | // from the referenced tsconfig.json - TypeScript does not merge them in 19 | } 20 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | import tailwindcss from '@tailwindcss/vite'; 4 | 5 | export default defineConfig({ 6 | plugins: [sveltekit(), tailwindcss()] 7 | }); 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/LovesAsuna/jetbrains_hacker 2 | 3 | go 1.24 4 | 5 | require ( 6 | github.com/dromara/carbon/v2 v2.6.3 7 | github.com/gin-gonic/gin v1.10.0 8 | github.com/spf13/cobra v1.9.1 9 | ) 10 | 11 | require ( 12 | github.com/bytedance/sonic v1.13.2 // indirect 13 | github.com/bytedance/sonic/loader v0.2.4 // indirect 14 | github.com/cloudwego/base64x v0.1.5 // indirect 15 | github.com/cloudwego/iasm v0.2.0 // indirect 16 | github.com/gabriel-vasile/mimetype v1.4.9 // indirect 17 | github.com/gin-contrib/sse v1.1.0 // indirect 18 | github.com/go-playground/locales v0.14.1 // indirect 19 | github.com/go-playground/universal-translator v0.18.1 // indirect 20 | github.com/go-playground/validator/v10 v10.26.0 // indirect 21 | github.com/goccy/go-json v0.10.5 // indirect 22 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 23 | github.com/json-iterator/go v1.1.12 // indirect 24 | github.com/klauspost/cpuid/v2 v2.2.10 // indirect 25 | github.com/leodido/go-urn v1.4.0 // indirect 26 | github.com/lovesasuna/sync v0.0.0-20250409122049-8bfa10ab236c // indirect 27 | github.com/mattn/go-isatty v0.0.20 // indirect 28 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 29 | github.com/modern-go/reflect2 v1.0.2 // indirect 30 | github.com/pelletier/go-toml/v2 v2.2.4 // indirect 31 | github.com/spf13/pflag v1.0.6 // indirect 32 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 33 | github.com/ugorji/go/codec v1.2.12 // indirect 34 | golang.org/x/arch v0.16.0 // indirect 35 | golang.org/x/crypto v0.37.0 // indirect 36 | golang.org/x/net v0.39.0 // indirect 37 | golang.org/x/sys v0.32.0 // indirect 38 | golang.org/x/text v0.24.0 // indirect 39 | google.golang.org/protobuf v1.36.6 // indirect 40 | gopkg.in/yaml.v3 v3.0.1 // indirect 41 | ) 42 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= 2 | github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= 3 | github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= 4 | github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= 5 | github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= 6 | github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= 7 | github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= 8 | github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= 9 | github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= 10 | github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 11 | github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= 12 | github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 13 | github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= 14 | github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 15 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 16 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/dromara/carbon/v2 v2.6.2 h1:ETogW/+yLDJfiSYyG74uuN3yN6NvLTC7E0Vi5WKyJuo= 19 | github.com/dromara/carbon/v2 v2.6.2/go.mod h1:Baj3A1uBBctJmpZWJd6/+WWnmIuY2pobR6IOpB6xigc= 20 | github.com/dromara/carbon/v2 v2.6.3 h1:suYXDpa4/xNUtg0cqMu3rp6sQW8ZAmX+F9qi9k+vogw= 21 | github.com/dromara/carbon/v2 v2.6.3/go.mod h1:Baj3A1uBBctJmpZWJd6/+WWnmIuY2pobR6IOpB6xigc= 22 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= 23 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 24 | github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= 25 | github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= 26 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 27 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 28 | github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= 29 | github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= 30 | github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= 31 | github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= 32 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 33 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 34 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 35 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 36 | github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= 37 | github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= 38 | github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= 39 | github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= 40 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 41 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 42 | github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= 43 | github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 44 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 45 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 46 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 47 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 48 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 49 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 50 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 51 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 52 | github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= 53 | github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= 54 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 55 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= 56 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 57 | github.com/lovesasuna/sync v0.0.0-20250409122049-8bfa10ab236c h1:uQKJLcIIgvnYSMxjGLEEYiN0gUrAnt4SKmldwkaFNVo= 58 | github.com/lovesasuna/sync v0.0.0-20250409122049-8bfa10ab236c/go.mod h1:XJIk9szX480mSUo019HXuVSQcM4tQaDViIxmc8ct48k= 59 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 60 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 61 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 62 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 63 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 64 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 65 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 66 | github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= 67 | github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 68 | github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 69 | github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 70 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 71 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 72 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= 73 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= 74 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 75 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 76 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 77 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 78 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 79 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 80 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 81 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 82 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 83 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 84 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 85 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 86 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 87 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 88 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 89 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= 90 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 91 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 92 | golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= 93 | golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 94 | golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U= 95 | golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= 96 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 97 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 98 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 99 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 100 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 101 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 102 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= 103 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= 104 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 107 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 108 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 109 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 110 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= 111 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 112 | golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= 113 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 114 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= 115 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 116 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 117 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 118 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 119 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 120 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 121 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 122 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 123 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 124 | -------------------------------------------------------------------------------- /internal/algo/rsa.go: -------------------------------------------------------------------------------- 1 | package algo 2 | 3 | import ( 4 | "crypto/rsa" 5 | "crypto/sha256" 6 | "errors" 7 | ) 8 | 9 | // The following code is copied from the standard library 10 | var hashPrefixes = map[string][]byte{ 11 | "SHA-256": {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, 12 | } 13 | 14 | var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size") 15 | 16 | func pkcs1v15ConstructEM(pub *rsa.PublicKey, hash string, hashed []byte) ([]byte, error) { 17 | // Special case: "" is used to indicate that the data is signed directly. 18 | var prefix []byte 19 | if hash != "" { 20 | var ok bool 21 | prefix, ok = hashPrefixes[hash] 22 | if !ok { 23 | return nil, errors.New("crypto/rsa: unsupported hash function") 24 | } 25 | } 26 | 27 | // EM = 0x00 || 0x01 || PS || 0x00 || T 28 | k := pub.Size() 29 | if k < len(prefix)+len(hashed)+2+8+1 { 30 | return nil, ErrMessageTooLong 31 | } 32 | em := make([]byte, k) 33 | em[1] = 1 34 | for i := 2; i < k-len(prefix)-len(hashed)-1; i++ { 35 | em[i] = 0xff 36 | } 37 | copy(em[k-len(prefix)-len(hashed):], prefix) 38 | copy(em[k-len(hashed):], hashed) 39 | return em, nil 40 | } 41 | 42 | func GetEM(pub *rsa.PublicKey, tbsCertificate []byte) ([]byte, error) { 43 | h := sha256.New() 44 | h.Write(tbsCertificate) 45 | signed := h.Sum(nil) 46 | return pkcs1v15ConstructEM(pub, "SHA-256", signed) 47 | } 48 | -------------------------------------------------------------------------------- /internal/cert/cert.go: -------------------------------------------------------------------------------- 1 | package cert 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/x509" 8 | "crypto/x509/pkix" 9 | "encoding/base64" 10 | "encoding/pem" 11 | "errors" 12 | "github.com/dromara/carbon/v2" 13 | "math/big" 14 | "os" 15 | "path/filepath" 16 | "strings" 17 | ) 18 | 19 | const JetProfileCertStr = `-----BEGIN CERTIFICATE----- 20 | MIIFOzCCAyOgAwIBAgIJANJssYOyg3nhMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV 21 | BAMMDUpldFByb2ZpbGUgQ0EwHhcNMTUxMDAyMTEwMDU2WhcNNDUxMDI0MTEwMDU2 22 | WjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMIICIjANBgkqhkiG9w0BAQEFAAOC 23 | Ag8AMIICCgKCAgEA0tQuEA8784NabB1+T2XBhpB+2P1qjewHiSajAV8dfIeWJOYG 24 | y+ShXiuedj8rL8VCdU+yH7Ux/6IvTcT3nwM/E/3rjJIgLnbZNerFm15Eez+XpWBl 25 | m5fDBJhEGhPc89Y31GpTzW0vCLmhJ44XwvYPntWxYISUrqeR3zoUQrCEp1C6mXNX 26 | EpqIGIVbJ6JVa/YI+pwbfuP51o0ZtF2rzvgfPzKtkpYQ7m7KgA8g8ktRXyNrz8bo 27 | iwg7RRPeqs4uL/RK8d2KLpgLqcAB9WDpcEQzPWegbDrFO1F3z4UVNH6hrMfOLGVA 28 | xoiQhNFhZj6RumBXlPS0rmCOCkUkWrDr3l6Z3spUVgoeea+QdX682j6t7JnakaOw 29 | jzwY777SrZoi9mFFpLVhfb4haq4IWyKSHR3/0BlWXgcgI6w6LXm+V+ZgLVDON52F 30 | LcxnfftaBJz2yclEwBohq38rYEpb+28+JBvHJYqcZRaldHYLjjmb8XXvf2MyFeXr 31 | SopYkdzCvzmiEJAewrEbPUaTllogUQmnv7Rv9sZ9jfdJ/cEn8e7GSGjHIbnjV2ZM 32 | Q9vTpWjvsT/cqatbxzdBo/iEg5i9yohOC9aBfpIHPXFw+fEj7VLvktxZY6qThYXR 33 | Rus1WErPgxDzVpNp+4gXovAYOxsZak5oTV74ynv1aQ93HSndGkKUE/qA/JECAwEA 34 | AaOBhzCBhDAdBgNVHQ4EFgQUo562SGdCEjZBvW3gubSgUouX8bMwSAYDVR0jBEEw 35 | P4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2Zp 36 | bGUgQ0GCCQDSbLGDsoN54TAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkq 37 | hkiG9w0BAQsFAAOCAgEAjrPAZ4xC7sNiSSqh69s3KJD3Ti4etaxcrSnD7r9rJYpK 38 | BMviCKZRKFbLv+iaF5JK5QWuWdlgA37ol7mLeoF7aIA9b60Ag2OpgRICRG79QY7o 39 | uLviF/yRMqm6yno7NYkGLd61e5Huu+BfT459MWG9RVkG/DY0sGfkyTHJS5xrjBV6 40 | hjLG0lf3orwqOlqSNRmhvn9sMzwAP3ILLM5VJC5jNF1zAk0jrqKz64vuA8PLJZlL 41 | S9TZJIYwdesCGfnN2AETvzf3qxLcGTF038zKOHUMnjZuFW1ba/12fDK5GJ4i5y+n 42 | fDWVZVUDYOPUixEZ1cwzmf9Tx3hR8tRjMWQmHixcNC8XEkVfztID5XeHtDeQ+uPk 43 | X+jTDXbRb+77BP6n41briXhm57AwUI3TqqJFvoiFyx5JvVWG3ZqlVaeU/U9e0gxn 44 | 8qyR+ZA3BGbtUSDDs8LDnE67URzK+L+q0F2BC758lSPNB2qsJeQ63bYyzf0du3wB 45 | /gb2+xJijAvscU3KgNpkxfGklvJD/oDUIqZQAnNcHe7QEf8iG2WqaMJIyXZlW3me 46 | 0rn+cgvxHPt6N4EBh5GgNZR4l0eaFEV+fxVsydOQYo1RIyFMXtafFBqQl6DDxujl 47 | FeU3FZ+Bcp12t7dlM4E0/sS1XdL47CfGVj4Bp+/VbF862HmkAbd7shs7sDQkHbU= 48 | -----END CERTIFICATE-----` 49 | 50 | const LicenseServerCertStr = `-----BEGIN CERTIFICATE----- 51 | MIIFTDCCAzSgAwIBAgIJAMCrW9HV+hjZMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNV 52 | BAMMEkxpY2Vuc2UgU2VydmVycyBDQTAgFw0xNjEwMTIxNDMwNTRaGA8yMTE2MTIy 53 | NzE0MzA1NFowHTEbMBkGA1UEAwwSTGljZW5zZSBTZXJ2ZXJzIENBMIICIjANBgkq 54 | hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoT7LvHj3JKK2pgc5f02z+xEiJDcvlBi6 55 | fIwrg/504UaMx3xWXAE5CEPelFty+QPRJnTNnSxqKQQmg2s/5tMJpL9lzGwXaV7a 56 | rrcsEDbzV4el5mIXUnk77Bm/QVv48s63iQqUjVmvjQt9SWG2J7+h6X3ICRvF1sQB 57 | yeat/cO7tkpz1aXXbvbAws7/3dXLTgAZTAmBXWNEZHVUTcwSg2IziYxL8HRFOH0+ 58 | GMBhHqa0ySmF1UTnTV4atIXrvjpABsoUvGxw+qOO2qnwe6ENEFWFz1a7pryVOHXg 59 | P+4JyPkI1hdAhAqT2kOKbTHvlXDMUaxAPlriOVw+vaIjIVlNHpBGhqTj1aqfJpLj 60 | qfDFcuqQSI4O1W5tVPRNFrjr74nDwLDZnOF+oSy4E1/WhL85FfP3IeQAIHdswNMJ 61 | y+RdkPZCfXzSUhBKRtiM+yjpIn5RBY+8z+9yeGocoxPf7l0or3YF4GUpud202zgy 62 | Y3sJqEsZksB750M0hx+vMMC9GD5nkzm9BykJS25hZOSsRNhX9InPWYYIi6mFm8QA 63 | 2Dnv8wxAwt2tDNgqa0v/N8OxHglPcK/VO9kXrUBtwCIfZigO//N3hqzfRNbTv/ZO 64 | k9lArqGtcu1hSa78U4fuu7lIHi+u5rgXbB6HMVT3g5GQ1L9xxT1xad76k2EGEi3F 65 | 9B+tSrvru70CAwEAAaOBjDCBiTAdBgNVHQ4EFgQUpsRiEz+uvh6TsQqurtwXMd4J 66 | 8VEwTQYDVR0jBEYwRIAUpsRiEz+uvh6TsQqurtwXMd4J8VGhIaQfMB0xGzAZBgNV 67 | BAMMEkxpY2Vuc2UgU2VydmVycyBDQYIJAMCrW9HV+hjZMAwGA1UdEwQFMAMBAf8w 68 | CwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQCJ9+GQWvBS3zsgPB+1PCVc 69 | oG6FY87N6nb3ZgNTHrUMNYdo7FDeol2DSB4wh/6rsP9Z4FqVlpGkckB+QHCvqU+d 70 | rYPe6QWHIb1kE8ftTnwapj/ZaBtF80NWUfYBER/9c6To5moW63O7q6cmKgaGk6zv 71 | St2IhwNdTX0Q5cib9ytE4XROeVwPUn6RdU/+AVqSOspSMc1WQxkPVGRF7HPCoGhd 72 | vqebbYhpahiMWfClEuv1I37gJaRtsoNpx3f/jleoC/vDvXjAznfO497YTf/GgSM2 73 | LCnVtpPQQ2vQbOfTjaBYO2MpibQlYpbkbjkd5ZcO5U5PGrQpPFrWcylz7eUC3c05 74 | UVeygGIthsA/0hMCioYz4UjWTgi9NQLbhVkfmVQ5lCVxTotyBzoubh3FBz+wq2Qt 75 | iElsBrCMR7UwmIu79UYzmLGt3/gBdHxaImrT9SQ8uqzP5eit54LlGbvGekVdAL5l 76 | DFwPcSB1IKauXZvi1DwFGPeemcSAndy+Uoqw5XGRqE6jBxS7XVI7/4BSMDDRBz1u 77 | a+JMGZXS8yyYT+7HdsybfsZLvkVmc9zVSDI7/MjVPdk6h0sLn+vuPC1bIi5edoNy 78 | PdiG2uPH5eDO6INcisyPpLS4yFKliaO4Jjap7yzLU9pbItoWgCAYa2NpxuxHJ0tB 79 | 7tlDFnvaRnQukqSG+VqNWg== 80 | -----END CERTIFICATE-----` 81 | 82 | var ( 83 | JetProfileCert *Certificate 84 | LicenseServerCert *Certificate 85 | ) 86 | 87 | func init() { 88 | var err error 89 | JetProfileCert, err = CreateCertFromPem([]byte(JetProfileCertStr)) 90 | if err != nil { 91 | panic(err) 92 | } 93 | LicenseServerCert, err = CreateCertFromPem([]byte(LicenseServerCertStr)) 94 | if err != nil { 95 | panic(err) 96 | } 97 | } 98 | 99 | type Certificate struct { 100 | parent *Certificate 101 | cert *x509.Certificate 102 | privateKey *rsa.PrivateKey 103 | } 104 | 105 | func (c *Certificate) WriteCertToFile(path string) error { 106 | if c.cert == nil { 107 | return errors.New("certificate is nil") 108 | } 109 | certificatePEM := &pem.Block{ 110 | Type: "CERTIFICATE", 111 | Bytes: c.cert.Raw, 112 | } 113 | bytes := pem.EncodeToMemory(certificatePEM) 114 | dir := filepath.Dir(path) 115 | _ = os.MkdirAll(dir, 0750) 116 | return os.WriteFile(path, bytes, 0666) 117 | } 118 | 119 | func (c *Certificate) WritePrivateKeyToFile(path string) error { 120 | if c.privateKey == nil { 121 | return errors.New("private key is nil") 122 | } 123 | privateKeyPEM := &pem.Block{ 124 | Type: "RSA PRIVATE KEY", 125 | Bytes: x509.MarshalPKCS1PrivateKey(c.privateKey), 126 | } 127 | bytes := pem.EncodeToMemory(privateKeyPEM) 128 | dir := filepath.Dir(path) 129 | _ = os.MkdirAll(dir, 0750) 130 | return os.WriteFile(path, bytes, 0666) 131 | } 132 | 133 | func (c *Certificate) Sign(hashAlgo crypto.Hash, content []byte) ([]byte, error) { 134 | if c.privateKey == nil { 135 | return nil, errors.New("private key is nil") 136 | } 137 | sha := hashAlgo.New() 138 | sha.Write(content) 139 | hashed := sha.Sum(nil) 140 | return rsa.SignPKCS1v15(rand.Reader, c.privateKey, hashAlgo, hashed) 141 | } 142 | 143 | func (c *Certificate) SignBase64(hashAlgo crypto.Hash, content []byte) (string, error) { 144 | signature, err := c.Sign(hashAlgo, content) 145 | if err != nil { 146 | return "", err 147 | } 148 | return base64.StdEncoding.EncodeToString(signature), nil 149 | } 150 | 151 | func (c *Certificate) Verify(hashAlgo crypto.Hash, content, signature []byte) error { 152 | sha := hashAlgo.New() 153 | sha.Write(content) 154 | hashed := sha.Sum(nil) 155 | return rsa.VerifyPKCS1v15(c.PublicKey(), hashAlgo, hashed, signature) 156 | } 157 | 158 | func (c *Certificate) RawTBS() ([]byte, error) { 159 | if c.cert == nil { 160 | return nil, errors.New("certificate is nil") 161 | } 162 | return c.cert.RawTBSCertificate, nil 163 | } 164 | 165 | func (c *Certificate) Raw() ([]byte, error) { 166 | if c.cert == nil { 167 | return nil, errors.New("certificate is nil") 168 | } 169 | return c.cert.Raw, nil 170 | } 171 | 172 | func (c *Certificate) RawBase64() (string, error) { 173 | raw, err := c.Raw() 174 | if err != nil { 175 | return "", err 176 | } 177 | return base64.StdEncoding.EncodeToString(raw), nil 178 | } 179 | 180 | func (c *Certificate) CommonName() string { 181 | if c.cert == nil { 182 | return "" 183 | } 184 | return c.cert.Subject.CommonName 185 | } 186 | 187 | func (c *Certificate) Signature() []byte { 188 | if c.cert == nil { 189 | return nil 190 | } 191 | return c.cert.Signature 192 | } 193 | 194 | func (c *Certificate) PublicKey() *rsa.PublicKey { 195 | if c.privateKey != nil { 196 | return &c.privateKey.PublicKey 197 | } 198 | if c.cert != nil { 199 | return c.cert.PublicKey.(*rsa.PublicKey) 200 | } 201 | return nil 202 | } 203 | 204 | func (c *Certificate) PrivateKey() *rsa.PrivateKey { 205 | if c.privateKey == nil { 206 | return nil 207 | } 208 | return c.privateKey 209 | } 210 | 211 | func GenerateFakeCertificate(parentCommonName, commonName, certPath, keyPath string) (*Certificate, error) { 212 | parentCert, err := GenerateCertificate(parentCommonName, nil) 213 | if err != nil { 214 | return nil, err 215 | } 216 | cert, err := GenerateCertificate(commonName, parentCert) 217 | if err != nil { 218 | return nil, err 219 | } 220 | if certPath != "" { 221 | if err = cert.WriteCertToFile(certPath); err != nil { 222 | return nil, err 223 | } 224 | } 225 | if keyPath != "" { 226 | if err = cert.WritePrivateKeyToFile(keyPath); err != nil { 227 | return nil, err 228 | } 229 | } 230 | return cert, nil 231 | } 232 | 233 | func GenerateCertificate(commonName string, parent *Certificate) (*Certificate, error) { 234 | serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) 235 | template := &x509.Certificate{ 236 | SerialNumber: serialNumber, 237 | Subject: pkix.Name{ 238 | CommonName: commonName, 239 | }, 240 | NotBefore: carbon.Now().StdTime(), 241 | NotAfter: carbon.Now().AddYears(2).StdTime(), 242 | SignatureAlgorithm: x509.SHA256WithRSA, 243 | } 244 | 245 | var ( 246 | parentTemplate *x509.Certificate 247 | parentPrivateKey *rsa.PrivateKey 248 | ) 249 | 250 | privateKey, err := rsa.GenerateKey(rand.Reader, 4096) 251 | if err != nil { 252 | return nil, err 253 | } 254 | if parent == nil { 255 | //template.BasicConstraintsValid = true 256 | //template.IsCA = true 257 | parentTemplate = template 258 | parentPrivateKey = privateKey 259 | } else { 260 | parentTemplate = parent.cert 261 | parentPrivateKey = parent.privateKey 262 | } 263 | certBytes, err := x509.CreateCertificate(rand.Reader, template, parentTemplate, &privateKey.PublicKey, parentPrivateKey) 264 | if err != nil { 265 | return nil, err 266 | } 267 | cert, err := x509.ParseCertificate(certBytes) 268 | if err != nil { 269 | return nil, err 270 | } 271 | certificate := &Certificate{ 272 | parent: parent, 273 | cert: cert, 274 | privateKey: privateKey, 275 | } 276 | if parent == nil { 277 | certificate.parent = certificate 278 | } 279 | return certificate, nil 280 | } 281 | 282 | const PemPrefix = "-----" 283 | 284 | func MustCreateCertFromFile(certPath, keyPath string) *Certificate { 285 | cert, err := CreateCertFromFile(certPath, keyPath) 286 | if err != nil { 287 | panic(err) 288 | } 289 | return cert 290 | } 291 | 292 | func CreateCertFromFile(certPath, keyPath string) (cert *Certificate, err error) { 293 | if cert, err = CreateCertFromFileWithoutPrivateKey(certPath); err != nil { 294 | return 295 | } 296 | if cert.privateKey, err = CreatePrivateKeyFromFile(keyPath); err != nil { 297 | return nil, err 298 | } 299 | return cert, nil 300 | } 301 | 302 | func CreateCertFromFileWithoutPrivateKey(certPath string) (*Certificate, error) { 303 | certBytes, err := os.ReadFile(certPath) 304 | if err != nil { 305 | return nil, err 306 | } 307 | var cert *Certificate 308 | if strings.HasPrefix(string(certBytes[:len(PemPrefix)]), PemPrefix) { 309 | cert, err = CreateCertFromPem(certBytes) 310 | } else { 311 | certBytes, _ = base64.StdEncoding.DecodeString(string(certBytes)) 312 | cert, err = CreateCertFromDer(certBytes) 313 | } 314 | if err != nil { 315 | return nil, err 316 | } 317 | return cert, nil 318 | } 319 | 320 | func CreatePrivateKeyFromFile(path string) (*rsa.PrivateKey, error) { 321 | keyBytes, err := os.ReadFile(path) 322 | if err != nil { 323 | return nil, err 324 | } 325 | var key *rsa.PrivateKey 326 | if strings.HasPrefix(string(keyBytes[:len(PemPrefix)]), PemPrefix) { 327 | key, err = CreatePrivateKeyFromPem(keyBytes) 328 | } else { 329 | key, err = CreatePrivateKeyFromDer(keyBytes) 330 | } 331 | if err != nil { 332 | return nil, err 333 | } 334 | return key, nil 335 | } 336 | 337 | func CreateCertFromPem(bytes []byte) (*Certificate, error) { 338 | block, _ := pem.Decode(bytes) 339 | return CreateCertFromDer(block.Bytes) 340 | } 341 | 342 | func CreatePrivateKeyFromPem(bytes []byte) (*rsa.PrivateKey, error) { 343 | block, _ := pem.Decode(bytes) 344 | return CreatePrivateKeyFromDer(block.Bytes) 345 | } 346 | 347 | func CreateCertFromDer(bytes []byte) (*Certificate, error) { 348 | cert, err := x509.ParseCertificate(bytes) 349 | if err != nil { 350 | return nil, err 351 | } 352 | return &Certificate{ 353 | cert: cert, 354 | }, nil 355 | } 356 | 357 | func CreatePrivateKeyFromDer(bytes []byte) (*rsa.PrivateKey, error) { 358 | key, err := x509.ParsePKCS1PrivateKey(bytes) 359 | if err != nil { 360 | return nil, err 361 | } 362 | return key, nil 363 | } 364 | -------------------------------------------------------------------------------- /internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/algo" 6 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 7 | "math/big" 8 | "strings" 9 | ) 10 | 11 | func BuildPowerConfig(certs ...[2]*cert.Certificate) string { 12 | lines := make([]string, 0, 4) 13 | lines = append(lines, "[Result]") 14 | for _, certPair := range certs { 15 | var ( 16 | x, z, r string 17 | y int 18 | subCert = certPair[0] 19 | realParentCert = certPair[1] 20 | ) 21 | bi := new(big.Int) 22 | bi.SetBytes(subCert.Signature()) 23 | x = bi.String() 24 | y = subCert.PublicKey().E 25 | z = realParentCert.PublicKey().N.String() 26 | bi = new(big.Int) 27 | subCertRawTBS, _ := subCert.RawTBS() 28 | em, err := algo.GetEM(cert.JetProfileCert.PublicKey(), subCertRawTBS) 29 | if err != nil { 30 | continue 31 | } 32 | bi.SetBytes(em) 33 | r = bi.String() 34 | lines = append(lines, fmt.Sprintf("EQUAL,%s,%d,%s->%s", x, y, z, r)) 35 | } 36 | return strings.Join(lines, "\n") 37 | } 38 | 39 | func BuildDnsConfig() string { 40 | builder := new(strings.Builder) 41 | builder.WriteString("[DNS]\n") 42 | builder.WriteString("EQUAL,jetbrains.com\n") 43 | builder.WriteString("EQUAL,plugin.obroom.com") 44 | return builder.String() 45 | } 46 | 47 | func BuildUrlConfig() string { 48 | builder := new(strings.Builder) 49 | builder.WriteString("[URL]\n") 50 | builder.WriteString("PREFIX,https://account.jetbrains.com/lservice/rpc/validateKey.action\n") 51 | builder.WriteString("PREFIX,https://account.jetbrains.com.cn/lservice/rpc/validateKey.action") 52 | return builder.String() 53 | } 54 | -------------------------------------------------------------------------------- /internal/license/code.go: -------------------------------------------------------------------------------- 1 | package license 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "github.com/lovesasuna/sync/coroutinegroup" 9 | "net/http" 10 | ) 11 | 12 | const ( 13 | DataBaseUrl = "https://data.services.jetbrains.com" 14 | PluginBaseUrl = "https://plugins.jetbrains.com" 15 | ) 16 | 17 | type ProductDto struct { 18 | Code string `json:"code"` 19 | SalesCode string `json:"salesCode"` 20 | Name string `json:"name"` 21 | Description string `json:"description"` 22 | ForSale bool `json:"forSale"` 23 | } 24 | 25 | func GetProductCode() (codes []string, err error) { 26 | resp, err := http.Get(fmt.Sprintf("%s/products?fields=name,code,forSale,salesCode,description", DataBaseUrl)) 27 | if err != nil { 28 | return nil, err 29 | } 30 | defer resp.Body.Close() 31 | var productList []ProductDto 32 | if err = json.NewDecoder(resp.Body).Decode(&productList); err != nil { 33 | return nil, err 34 | } 35 | for _, product := range productList { 36 | codes = append(codes, product.Code) 37 | if product.ForSale && product.SalesCode != "" { 38 | codes = append(codes, product.SalesCode) 39 | } 40 | } 41 | return 42 | } 43 | 44 | type PluginDto struct { 45 | ID int32 `json:"id"` 46 | XMLID string `json:"xmlId"` 47 | Link string `json:"link"` 48 | Name string `json:"name"` 49 | Preview string `json:"preview"` 50 | Downloads int `json:"downloads"` 51 | PricingModel string `json:"pricingModel"` 52 | Icon string `json:"icon"` 53 | PreviewImage string `json:"previewImage"` 54 | Cdate int64 `json:"cdate"` 55 | Rating float64 `json:"rating"` 56 | HasSource bool `json:"hasSource"` 57 | Tags []string `json:"tags"` 58 | Vendor Vendor `json:"vendor"` 59 | } 60 | 61 | type PluginDetail struct { 62 | ID int32 `json:"id"` 63 | Name string `json:"name"` 64 | Link string `json:"link"` 65 | Approve bool `json:"approve"` 66 | XMLID string `json:"xmlId"` 67 | Description string `json:"description"` 68 | CustomIdeList bool `json:"customIdeList"` 69 | Preview string `json:"preview"` 70 | DocText string `json:"docText"` 71 | Cdate int64 `json:"cdate"` 72 | Family string `json:"family"` 73 | Downloads int `json:"downloads"` 74 | PurchaseInfo PurchaseInfo `json:"purchaseInfo"` 75 | Vendor Vendor `json:"vendor"` 76 | Urls Urls `json:"urls"` 77 | Tags []Tags `json:"tags"` 78 | HasUnapprovedUpdate bool `json:"hasUnapprovedUpdate"` 79 | PricingModel string `json:"pricingModel"` 80 | Screens []Screens `json:"screens"` 81 | Icon string `json:"icon"` 82 | IsHidden bool `json:"isHidden"` 83 | IsMonetizationAvailable bool `json:"isMonetizationAvailable"` 84 | IsBlocked bool `json:"isBlocked"` 85 | IsModificationAllowed bool `json:"isModificationAllowed"` 86 | } 87 | 88 | type PurchaseInfo struct { 89 | ProductCode string `json:"productCode"` 90 | BuyURL interface{} `json:"buyUrl"` 91 | PurchaseTerms interface{} `json:"purchaseTerms"` 92 | Optional bool `json:"optional"` 93 | TrialPeriod int `json:"trialPeriod"` 94 | } 95 | 96 | type Details struct { 97 | City string `json:"city"` 98 | Address string `json:"address"` 99 | State interface{} `json:"state"` 100 | Zip string `json:"zip"` 101 | Phone string `json:"phone"` 102 | } 103 | 104 | type Vendor struct { 105 | Type string `json:"type"` 106 | ID int `json:"id"` 107 | Name string `json:"name"` 108 | URL string `json:"url"` 109 | Link string `json:"link"` 110 | PublicName string `json:"publicName"` 111 | Email string `json:"email"` 112 | CountryCode string `json:"countryCode"` 113 | Country string `json:"country"` 114 | IsVerified bool `json:"isVerified"` 115 | VendorID int `json:"vendorId"` 116 | Details Details `json:"details"` 117 | IsTrader bool `json:"isTrader"` 118 | } 119 | 120 | type Urls struct { 121 | URL string `json:"url"` 122 | ForumURL string `json:"forumUrl"` 123 | LicenseURL string `json:"licenseUrl"` 124 | PrivacyPolicyURL string `json:"privacyPolicyUrl"` 125 | BugtrackerURL string `json:"bugtrackerUrl"` 126 | DocURL string `json:"docUrl"` 127 | SourceCodeURL string `json:"sourceCodeUrl"` 128 | } 129 | 130 | type Tags struct { 131 | ID int `json:"id"` 132 | Name string `json:"name"` 133 | Privileged bool `json:"privileged"` 134 | Searchable bool `json:"searchable"` 135 | Link string `json:"link"` 136 | } 137 | 138 | type Screens struct { 139 | URL string `json:"url"` 140 | } 141 | 142 | func GetPluginCode(max, offset int32, keyword string) (codes []string, err error) { 143 | resp, err := http.Get(fmt.Sprintf("%s/api/searchPlugins?max=%d&offset=%d&search=%s", PluginBaseUrl, max, offset, keyword)) 144 | if err != nil { 145 | return nil, err 146 | } 147 | defer resp.Body.Close() 148 | 149 | var pluginListResp struct { 150 | Plugins []*PluginDto `json:"plugins"` 151 | } 152 | err = json.NewDecoder(resp.Body).Decode(&pluginListResp) 153 | if err != nil { 154 | return nil, err 155 | } 156 | 157 | pluginDetailChan := make(chan *PluginDetail, len(pluginListResp.Plugins)) 158 | group, _ := coroutinegroup.WithContext(context.Background()) 159 | group.SetMaxErrorTask(int32(len(pluginListResp.Plugins) / 3)) 160 | group.SetGlobalRetryTimes(1) 161 | for _, plugin := range pluginListResp.Plugins { 162 | if plugin.PricingModel == "FREE" { 163 | continue 164 | } 165 | if plugin.Icon != "" { 166 | plugin.Icon = PluginBaseUrl + plugin.Icon 167 | } 168 | p := plugin 169 | group.Go( 170 | func(ctx context.Context) error { 171 | detail, err := getDetailByPluginId(p.ID) 172 | if err != nil { 173 | return err 174 | } 175 | pluginDetailChan <- detail 176 | return nil 177 | }, 178 | ) 179 | } 180 | errs := group.Wait() 181 | close(pluginDetailChan) 182 | if len(errs) > 0 { 183 | return nil, errors.Join(errs...) 184 | } 185 | for detail := range pluginDetailChan { 186 | code := detail.PurchaseInfo.ProductCode 187 | if code != "" { 188 | codes = append(codes, code) 189 | } 190 | } 191 | return 192 | } 193 | 194 | func getDetailByPluginId(id int32) (detail *PluginDetail, err error) { 195 | resp, err := http.Get(fmt.Sprintf("%s/api/plugins/%d", PluginBaseUrl, id)) 196 | if err != nil { 197 | return nil, err 198 | } 199 | defer resp.Body.Close() 200 | 201 | detail = new(PluginDetail) 202 | err = json.NewDecoder(resp.Body).Decode(detail) 203 | return 204 | } 205 | -------------------------------------------------------------------------------- /internal/license/license.go: -------------------------------------------------------------------------------- 1 | package license 2 | 3 | import ( 4 | "crypto" 5 | "encoding/base64" 6 | "encoding/json" 7 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 8 | "github.com/dromara/carbon/v2" 9 | "strings" 10 | ) 11 | 12 | type License struct { 13 | LicenseID string `json:"licenseId"` 14 | LicenseeName string `json:"licenseeName"` 15 | AssigneeName string `json:"assigneeName"` 16 | AssigneeEmail string `json:"assigneeEmail"` 17 | LicenseRestriction string `json:"licenseRestriction"` 18 | CheckConcurrentUse bool `json:"checkConcurrentUse"` 19 | Products []Product `json:"products"` 20 | Metadata string `json:"metadata"` 21 | Hash string `json:"hash"` 22 | GracePeriodDays int `json:"gracePeriodDays"` 23 | AutoProlongated bool `json:"autoProlongated"` 24 | IsAutoProlongated bool `json:"isAutoProlongated"` 25 | } 26 | 27 | type Product struct { 28 | Code string `json:"code"` 29 | FallbackDate string `json:"fallbackDate"` 30 | PaidUpTo string `json:"paidUpTo"` 31 | } 32 | 33 | func GenerateLicenseCode(cert *cert.Certificate, licenseId, licenseeName, assigneeName, assigneeEmail, time string, codes ...string) (string, error) { 34 | license, err := GenerateLicense( 35 | licenseId, 36 | licenseeName, 37 | assigneeName, 38 | assigneeEmail, 39 | time, 40 | codes..., 41 | ) 42 | if err != nil { 43 | return "", err 44 | } 45 | licenseJs, _ := json.Marshal(license) 46 | licensePartBase64 := base64.StdEncoding.EncodeToString(licenseJs) 47 | 48 | certPartBase64, _ := cert.RawBase64() 49 | 50 | signatureBytes, _ := cert.Sign(crypto.SHA1, licenseJs) 51 | signatureBase64 := base64.StdEncoding.EncodeToString(signatureBytes) 52 | 53 | return strings.Join([]string{licenseId, licensePartBase64, signatureBase64, certPartBase64}, "-"), nil 54 | } 55 | 56 | func GenerateLicense(licenseId, licenseeName, assigneeName, assigneeEmail, time string, codes ...string) (*License, error) { 57 | fallBackDate := carbon.Now().SetLayout(carbon.DateLayout).String() 58 | paidUpTo := carbon.ParseByLayout(time, carbon.DateLayout).String() 59 | 60 | products := make([]Product, 0, len(codes)) 61 | for _, code := range codes { 62 | products = append(products, Product{ 63 | Code: code, 64 | FallbackDate: fallBackDate, 65 | PaidUpTo: paidUpTo, 66 | }) 67 | } 68 | 69 | license := &License{ 70 | LicenseID: licenseId, 71 | LicenseeName: licenseeName, 72 | AssigneeName: assigneeName, 73 | AssigneeEmail: assigneeEmail, 74 | Products: products, 75 | Metadata: "0120230102PPAA013009", 76 | Hash: "41472961/0:1563609451", 77 | GracePeriodDays: 7, 78 | AutoProlongated: true, 79 | IsAutoProlongated: true, 80 | } 81 | return license, nil 82 | } 83 | -------------------------------------------------------------------------------- /internal/util/random.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "math/rand" 4 | 5 | const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 6 | 7 | func GetRandomString(length int) string { 8 | if length <= 0 { 9 | return "" 10 | } 11 | bytes := make([]byte, length) 12 | for i := 0; i < length; i++ { 13 | bytes[i] = letters[rand.Intn(len(letters))] 14 | } 15 | return string(bytes) 16 | } 17 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | default: backend frontend caddy 2 | caddy run --config ./Caddyfile 3 | 4 | caddy: 5 | mkdir -p /var/log/caddy 6 | wget -q -O /usr/local/bin/caddy "https://caddyserver.com/api/download?os=linux&arch=amd64" && chmod +x /usr/local/bin/caddy 7 | 8 | frontend: 9 | just frontend/ 10 | 11 | backend: build_backend 12 | ./jetbrains_hacker run-server --addr :8080 & 13 | 14 | build_backend: 15 | go mod tidy 16 | go build -v -o jetbrains_hacker -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /server/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | var Config *ServerConfig 4 | 5 | type ServerConfig struct { 6 | Addr string 7 | Licensee string 8 | UserCertPath string 9 | UserPrivateKeyPath string 10 | LicenseServerCertPath string 11 | LicenseServerPrivateKeyPath string 12 | } 13 | 14 | func InitServerConfig(c *ServerConfig) { 15 | Config = c 16 | } 17 | -------------------------------------------------------------------------------- /server/handler/base.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "crypto" 5 | "encoding/xml" 6 | "fmt" 7 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 8 | "net/http" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | type BaseRequest struct { 14 | Salt string `form:"salt"` 15 | UserName string `form:"userName"` 16 | MachineId string `form:"machineId"` 17 | } 18 | 19 | type Helper struct { 20 | *CertPool 21 | } 22 | 23 | func NewHelper(pool *CertPool) *Helper { 24 | response := &Helper{ 25 | CertPool: pool, 26 | } 27 | return response 28 | } 29 | 30 | func (b *Helper) GenerateConfirmationStamp(machineId string) string { 31 | timeStamp := time.Now().UnixMilli() 32 | licenseStr := fmt.Sprintf("%d:%s", timeStamp, machineId) 33 | licenseServerCert := b.LicenseServerCert 34 | signatureBase64, _ := licenseServerCert.SignBase64(crypto.SHA1, []byte(licenseStr)) 35 | rawUserCertBase64, _ := licenseServerCert.RawBase64() 36 | return fmt.Sprintf("%s:SHA1withRSA:%s:%s", licenseStr, signatureBase64, rawUserCertBase64) 37 | } 38 | 39 | func (b *Helper) GenerateLeaseSignature(serverLease string) string { 40 | leaseSignature, _ := b.UserCert.SignBase64(crypto.SHA512, []byte(serverLease)) 41 | rawUserCertBase64, _ := b.UserCert.RawBase64() 42 | return fmt.Sprintf("SHA512withRSA-%s-%s", leaseSignature, rawUserCertBase64) 43 | } 44 | 45 | func (b *Helper) GetServerUid() string { 46 | serverUid := "custom" 47 | licenseServerCommonName := b.LicenseServerCert.CommonName() 48 | if strings.Contains(licenseServerCommonName, ".") { 49 | serverUid = strings.Split(licenseServerCommonName, ".")[0] 50 | } 51 | return serverUid 52 | } 53 | 54 | func (b *Helper) Sign(content []byte) (result []byte, err error) { 55 | signAlgo := crypto.SHA1 56 | signature, err := b.LicenseServerCert.SignBase64(signAlgo, content) 57 | if err != nil { 58 | return nil, err 59 | } 60 | rawLicenseServerCertBase64, _ := b.LicenseServerCert.RawBase64() 61 | return []byte(fmt.Sprintf("", signature, rawLicenseServerCertBase64)), nil 62 | } 63 | 64 | type Signable interface { 65 | Sign(content []byte) (result []byte, err error) 66 | } 67 | 68 | type SignedResponse struct { 69 | Signable 70 | } 71 | 72 | func (t *SignedResponse) Render(w http.ResponseWriter) error { 73 | t.WriteContentType(w) 74 | content, err := xml.Marshal(t.Signable) 75 | if err != nil { 76 | return err 77 | } 78 | signature, err := t.Signable.Sign(content) 79 | if err != nil { 80 | return err 81 | } 82 | _, err = w.Write(signature) 83 | if err != nil { 84 | return err 85 | } 86 | _, _ = w.Write([]byte("\n")) 87 | _, err = w.Write(content) 88 | return err 89 | } 90 | 91 | func (t *SignedResponse) WriteContentType(w http.ResponseWriter) { 92 | w.Header()["Content-Type"] = []string{"text/xml; charset=utf-8"} 93 | } 94 | 95 | const CertPoolKey = "cert_pool" 96 | 97 | type CertPool struct { 98 | LicenseServerCert *cert.Certificate 99 | UserCert *cert.Certificate 100 | } 101 | -------------------------------------------------------------------------------- /server/handler/config.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/config" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | ) 9 | 10 | func Config(context *gin.Context) { 11 | var ( 12 | configText string 13 | _type = context.Param("type") 14 | ) 15 | switch _type { 16 | case "dns": 17 | configText = config.BuildDnsConfig() 18 | case "url": 19 | configText = config.BuildUrlConfig() 20 | default: 21 | _type = "power" 22 | pool := context.Value(CertPoolKey).(*CertPool) 23 | configText = config.BuildPowerConfig( 24 | [2]*cert.Certificate{ 25 | pool.UserCert, cert.JetProfileCert, 26 | }, 27 | [2]*cert.Certificate{ 28 | pool.LicenseServerCert, cert.LicenseServerCert, 29 | }, 30 | ) 31 | } 32 | context.JSON( 33 | http.StatusOK, 34 | struct { 35 | Type string `json:"type"` 36 | Config string `json:"config"` 37 | }{ 38 | Type: _type, 39 | Config: configText, 40 | }, 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /server/handler/license.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/internal/license" 5 | "github.com/gin-gonic/gin" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | func License(context *gin.Context) { 11 | pool := context.Value(CertPoolKey).(*CertPool) 12 | type Param struct { 13 | LicenseId string `form:"licenseId"` 14 | Name string `form:"name"` 15 | User string `form:"user"` 16 | Email string `form:"email"` 17 | Time string `form:"time"` 18 | Codes string `form:"codes"` 19 | } 20 | param := new(Param) 21 | err := context.Bind(param) 22 | if err != nil { 23 | _ = context.AbortWithError(http.StatusInternalServerError, err) 24 | return 25 | } 26 | licenseCode, err := license.GenerateLicenseCode( 27 | pool.UserCert, 28 | param.LicenseId, 29 | param.Name, 30 | param.User, 31 | param.Email, 32 | param.Time, 33 | strings.Split(param.Codes, ",")..., 34 | ) 35 | if err != nil { 36 | _ = context.AbortWithError(http.StatusInternalServerError, err) 37 | return 38 | } 39 | context.JSON( 40 | http.StatusOK, 41 | struct { 42 | LicenseCode string `json:"licenseCode"` 43 | }{ 44 | LicenseCode: licenseCode, 45 | }, 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /server/handler/obtain_ticket.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/util" 6 | "github.com/LovesAsuna/jetbrains_hacker/server/config" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | ) 10 | 11 | func ObtainTicket(context *gin.Context) { 12 | response, err := NewObtainTicketResponse(context) 13 | if err != nil { 14 | _ = context.AbortWithError(http.StatusInternalServerError, err) 15 | return 16 | } 17 | context.Render(http.StatusOK, &SignedResponse{response}) 18 | } 19 | 20 | type ObtainTicketResponse struct { 21 | *Helper `xml:"-"` 22 | Action string `xml:"action"` 23 | ConfirmationStamp string `xml:"confirmationStamp"` 24 | LeaseSignature string `xml:"leaseSignature"` 25 | Message string `xml:"message"` 26 | ProlongationPeriod int `xml:"prolongationPeriod,omitempty"` 27 | ResponseCode string `xml:"responseCode"` 28 | Salt string `xml:"salt"` 29 | ServerLease string `xml:"serverLease"` 30 | ServerUid string `xml:"serverUid"` 31 | TicketID string `xml:"ticketId"` 32 | TicketProperties string `xml:"ticketProperties"` 33 | ValidationDeadline int `xml:"validationDeadlinePeriod"` 34 | ValidationPeriod int `xml:"validationPeriod"` 35 | } 36 | 37 | func NewObtainTicketResponse(context *gin.Context) (*ObtainTicketResponse, error) { 38 | baseRequest := new(BaseRequest) 39 | if err := context.Bind(baseRequest); err != nil { 40 | return nil, err 41 | } 42 | helper := NewHelper(context.Value(CertPoolKey).(*CertPool)) 43 | serverUid := helper.GetServerUid() 44 | serverLease := "4102415999000:" + serverUid 45 | licensee := config.Config.Licensee 46 | if licensee == "" { 47 | licensee = baseRequest.UserName 48 | } 49 | return &ObtainTicketResponse{ 50 | Helper: helper, 51 | Action: "NONE", 52 | ConfirmationStamp: helper.GenerateConfirmationStamp(baseRequest.MachineId), 53 | LeaseSignature: helper.GenerateLeaseSignature(serverLease), 54 | Message: "", 55 | ProlongationPeriod: 600000, 56 | ResponseCode: "OK", 57 | Salt: baseRequest.Salt, 58 | ServerLease: serverLease, 59 | ServerUid: serverUid, 60 | TicketID: util.GetRandomString(10), 61 | TicketProperties: fmt.Sprintf("licensee=%s", licensee), 62 | ValidationDeadline: -1, 63 | ValidationPeriod: 60000000, 64 | }, nil 65 | } 66 | -------------------------------------------------------------------------------- /server/handler/ping.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | ) 7 | 8 | func Ping(context *gin.Context) { 9 | response, err := NewPingResponse(context) 10 | if err != nil { 11 | _ = context.AbortWithError(http.StatusInternalServerError, err) 12 | return 13 | } 14 | context.Render(http.StatusOK, &SignedResponse{response}) 15 | } 16 | 17 | type PingResponse struct { 18 | *Helper `xml:"-"` 19 | Action string `xml:"action"` 20 | ConfirmationStamp string `xml:"confirmationStamp"` 21 | LeaseSignature string `xml:"leaseSignature"` 22 | Message string `xml:"message"` 23 | ResponseCode string `xml:"responseCode"` 24 | Salt string `xml:"salt"` 25 | ServerLease string `xml:"serverLease"` 26 | ServerUid string `xml:"serverUid"` 27 | ValidationDeadline int `xml:"validationDeadlinePeriod"` 28 | ValidationPeriod int `xml:"validationPeriod"` 29 | } 30 | 31 | func NewPingResponse(context *gin.Context) (*PingResponse, error) { 32 | baseRequest := new(BaseRequest) 33 | if err := context.Bind(baseRequest); err != nil { 34 | return nil, err 35 | } 36 | helper := NewHelper(context.Value(CertPoolKey).(*CertPool)) 37 | serverUid := helper.GetServerUid() 38 | serverLease := "4102415999000:" + serverUid 39 | return &PingResponse{ 40 | Helper: helper, 41 | Action: "NONE", 42 | ConfirmationStamp: helper.GenerateConfirmationStamp(baseRequest.MachineId), 43 | LeaseSignature: helper.GenerateLeaseSignature(serverLease), 44 | Message: "", 45 | ResponseCode: "OK", 46 | Salt: baseRequest.Salt, 47 | ServerLease: serverLease, 48 | ServerUid: serverUid, 49 | ValidationDeadline: -1, 50 | ValidationPeriod: 60000000, 51 | }, nil 52 | } 53 | -------------------------------------------------------------------------------- /server/handler/release_ticket.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | ) 7 | 8 | func ReleaseTicket(context *gin.Context) { 9 | response, err := NewReleaseTicketResponse(context) 10 | if err != nil { 11 | _ = context.AbortWithError(http.StatusInternalServerError, err) 12 | return 13 | } 14 | context.Render(http.StatusOK, &SignedResponse{response}) 15 | } 16 | 17 | type ReleaseTicketResponse struct { 18 | *Helper `xml:"-"` 19 | Action string `xml:"action"` 20 | ConfirmationStamp string `xml:"confirmationStamp"` 21 | LeaseSignature string `xml:"leaseSignature"` 22 | Message string `xml:"message"` 23 | ResponseCode string `xml:"responseCode"` 24 | Salt string `xml:"salt"` 25 | ServerLease string `xml:"serverLease"` 26 | ServerUid string `xml:"serverUid"` 27 | ValidationDeadline int `xml:"validationDeadlinePeriod"` 28 | ValidationPeriod int `xml:"validationPeriod"` 29 | } 30 | 31 | func NewReleaseTicketResponse(context *gin.Context) (*ReleaseTicketResponse, error) { 32 | baseRequest := new(BaseRequest) 33 | if err := context.Bind(baseRequest); err != nil { 34 | return nil, err 35 | } 36 | helper := NewHelper(context.Value(CertPoolKey).(*CertPool)) 37 | serverUid := helper.GetServerUid() 38 | serverLease := "4102415999000:" + serverUid 39 | 40 | return &ReleaseTicketResponse{ 41 | Helper: nil, 42 | Action: "NONE", 43 | ConfirmationStamp: helper.GenerateConfirmationStamp(baseRequest.MachineId), 44 | LeaseSignature: helper.GenerateLeaseSignature(serverLease), 45 | Message: "", 46 | ResponseCode: "OK", 47 | Salt: baseRequest.Salt, 48 | ServerLease: serverLease, 49 | ServerUid: serverUid, 50 | ValidationDeadline: -1, 51 | ValidationPeriod: 600000, 52 | }, nil 53 | } 54 | -------------------------------------------------------------------------------- /server/middleware/certificate.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "github.com/LovesAsuna/jetbrains_hacker/internal/cert" 6 | "github.com/LovesAsuna/jetbrains_hacker/server/config" 7 | "github.com/LovesAsuna/jetbrains_hacker/server/handler" 8 | "github.com/gin-gonic/gin" 9 | "net/http" 10 | "os" 11 | "sync" 12 | ) 13 | 14 | var certCache = struct { 15 | userCert *cert.Certificate 16 | licenseServerCert *cert.Certificate 17 | rwLock sync.RWMutex 18 | }{} 19 | 20 | func InjectCertificate(context *gin.Context) { 21 | certCache.rwLock.RLock() 22 | if certCache.userCert == nil || certCache.licenseServerCert == nil { 23 | certCache.rwLock.RUnlock() 24 | certCache.rwLock.Lock() 25 | if certCache.userCert != nil && certCache.licenseServerCert != nil { 26 | certCache.rwLock.Unlock() 27 | } else { 28 | var err error 29 | isExist := func(filePath string) bool { 30 | _, err := os.Stat(filePath) 31 | return err == nil || !os.IsNotExist(err) 32 | } 33 | if isExist(config.Config.UserCertPath) && isExist(config.Config.UserPrivateKeyPath) { 34 | certCache.userCert, err = cert.CreateCertFromFile(config.Config.UserCertPath, config.Config.UserPrivateKeyPath) 35 | if err != nil { 36 | certCache.rwLock.Lock() 37 | _ = context.AbortWithError(http.StatusInternalServerError, err) 38 | return 39 | } 40 | } else { 41 | if certCache.userCert, err = cert.GenerateFakeCertificate( 42 | cert.JetProfileCert.CommonName(), 43 | "create by license server", 44 | config.Config.UserCertPath, 45 | config.Config.UserPrivateKeyPath, 46 | ); err != nil { 47 | certCache.rwLock.Lock() 48 | _ = context.AbortWithError(http.StatusInternalServerError, err) 49 | return 50 | } 51 | } 52 | 53 | if isExist(config.Config.LicenseServerCertPath) && isExist(config.Config.LicenseServerPrivateKeyPath) { 54 | certCache.licenseServerCert, err = cert.CreateCertFromFile(config.Config.LicenseServerCertPath, config.Config.LicenseServerPrivateKeyPath) 55 | if err != nil { 56 | certCache.rwLock.Lock() 57 | _ = context.AbortWithError(http.StatusInternalServerError, err) 58 | return 59 | } 60 | } else { 61 | if certCache.licenseServerCert, err = cert.GenerateFakeCertificate( 62 | cert.LicenseServerCert.CommonName(), 63 | fmt.Sprintf("%s.lsrv.jetbrains.com", "license_server"), 64 | config.Config.LicenseServerCertPath, 65 | config.Config.LicenseServerPrivateKeyPath, 66 | ); err != nil { 67 | certCache.rwLock.Lock() 68 | _ = context.AbortWithError(http.StatusInternalServerError, err) 69 | return 70 | } 71 | } 72 | certCache.rwLock.Unlock() 73 | } 74 | } else { 75 | certCache.rwLock.RUnlock() 76 | } 77 | 78 | certPool := &handler.CertPool{ 79 | UserCert: certCache.userCert, 80 | LicenseServerCert: certCache.licenseServerCert, 81 | } 82 | context.Set(handler.CertPoolKey, certPool) 83 | } 84 | -------------------------------------------------------------------------------- /server/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func SetMiddleWare(engine *gin.Engine) { 6 | engine.Use(InjectCertificate) 7 | } 8 | -------------------------------------------------------------------------------- /server/router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/server/handler" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | func SetRouter(engine *gin.Engine) { 9 | engine.Handle("GET", "/rpc/obtainTicket.action", handler.ObtainTicket) 10 | engine.Handle("GET", "/rpc/ping.action", handler.Ping) 11 | engine.Handle("GET", "/rpc/releaseTicket.action", handler.ReleaseTicket) 12 | engine.Handle("GET", "/rpc/license", handler.License) 13 | engine.Handle("GET", "/config/:type", handler.Config) 14 | } 15 | -------------------------------------------------------------------------------- /server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/LovesAsuna/jetbrains_hacker/server/config" 5 | "github.com/LovesAsuna/jetbrains_hacker/server/middleware" 6 | "github.com/LovesAsuna/jetbrains_hacker/server/router" 7 | "github.com/gin-gonic/gin" 8 | ) 9 | 10 | func RunServer() error { 11 | gin.SetMode(gin.ReleaseMode) 12 | engine := gin.Default() 13 | middleware.SetMiddleWare(engine) 14 | router.SetRouter(engine) 15 | return engine.Run(config.Config.Addr) 16 | } 17 | --------------------------------------------------------------------------------