Browse Source

init

tags/v1.0.0
luamas 2 years ago
commit
28c602102a
21 changed files with 420 additions and 0 deletions
  1. +25
    -0
      .gitignore
  2. +3
    -0
      Dockerfile
  3. +29
    -0
      build.sh
  4. BIN
      license-server/license-server_darwin_386
  5. BIN
      license-server/license-server_darwin_amd64
  6. BIN
      license-server/license-server_linux_386
  7. BIN
      license-server/license-server_linux_amd64
  8. BIN
      license-server/license-server_linux_arm
  9. BIN
      license-server/license-server_linux_mips
  10. BIN
      license-server/license-server_linux_mips64
  11. BIN
      license-server/license-server_linux_mips64le
  12. BIN
      license-server/license-server_linux_mipsle
  13. BIN
      license-server/license-server_netbsd_386
  14. BIN
      license-server/license-server_netbsd_amd64
  15. BIN
      license-server/license-server_netbsd_arm
  16. BIN
      license-server/license-server_openbsd_386
  17. BIN
      license-server/license-server_openbsd_amd64
  18. BIN
      license-server/license-server_windows_386.exe
  19. BIN
      license-server/license-server_windows_amd64.exe
  20. +356
    -0
      main.go
  21. +7
    -0
      run.sh

+ 25
- 0
.gitignore View File

@@ -0,0 +1,25 @@
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

+ 3
- 0
Dockerfile View File

@@ -0,0 +1,3 @@
FROM scratch
ADD license-server/license-server_linux_amd64 /license-server
ENTRYPOINT ["/license-server"]

+ 29
- 0
build.sh View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash

name=license-server/license-server

# mac
CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build -o "$name"_darwin_386
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o "$name"_darwin_amd64

# linux
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -o "$name"_linux_386
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "$name"_linux_amd64
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o "$name"_linux_arm
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -o "$name"_linux_mips
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -o "$name"_linux_mipsle
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -o "$name"_linux_mips64
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -o "$name"_linux_mips64le

# netbsd
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -o "$name"_netbsd_386
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -o "$name"_netbsd_amd64
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm go build -o "$name"_netbsd_arm

# openbsd
CGO_ENABLED=0 GOOS=openbsd GOARCH=386 go build -o "$name"_openbsd_386
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build -o "$name"_openbsd_amd64

# windows
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o "$name"_windows_386.exe
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o "$name"_windows_amd64.exe

BIN
license-server/license-server_darwin_386 View File


BIN
license-server/license-server_darwin_amd64 View File


BIN
license-server/license-server_linux_386 View File


BIN
license-server/license-server_linux_amd64 View File


BIN
license-server/license-server_linux_arm View File


BIN
license-server/license-server_linux_mips View File


BIN
license-server/license-server_linux_mips64 View File


BIN
license-server/license-server_linux_mips64le View File


BIN
license-server/license-server_linux_mipsle View File


BIN
license-server/license-server_netbsd_386 View File


BIN
license-server/license-server_netbsd_amd64 View File


BIN
license-server/license-server_netbsd_arm View File


BIN
license-server/license-server_openbsd_386 View File


BIN
license-server/license-server_openbsd_amd64 View File


BIN
license-server/license-server_windows_386.exe View File


BIN
license-server/license-server_windows_amd64.exe View File


+ 356
- 0
main.go View File

@@ -0,0 +1,356 @@
package main

import (
"encoding/base64"
"encoding/json"
"encoding/xml"
"flag"
"strconv"
"strings"
"net/http"
"os"
"log"
"regexp"
"time"
"crypto/x509"
"crypto/sha1"
"crypto/rsa"
"crypto"
"encoding/pem"
"crypto/rand"
"crypto/md5"
"encoding/hex"
)

type JrebelBaseResponse struct {
ServerVersion string `json:"serverVersion"`
ServerProtocolVersion string `json:"serverProtocolVersion"`
ServerGuid string `json:"serverGuid"`
GroupType string `json:"groupType"`
}

type JrebelBaseDto struct {
JrebelBaseResponse
Id int `json:"id"`
LicenseType int `json:"licenseType"`
EvaluationLicense bool `json:"evaluationLicense"`
Signature string `json:"signature"`
ServerRandomness string `json:"serverRandomness"`
SeatPoolType string `json:"seatPoolType"`
}

type JrebelCreateDto struct {
JrebelBaseDto
StatusCode string `json:"statusCode"`
Offline bool `json:"offline"`
ValidFrom int64 `json:"validFrom,omitempty"`
ValidUntil int64 `json:"validUntil,omitempty"`
Company string `json:"company"`
OrderId string `json:"orderId"`
ZeroIds []string `json:"zeroIds"`
LicenseValidFrom int64 `json:"licenseValidFrom"`
LicenseValidUntil int64 `json:"licenseValidUntil"`
}



type JrebelSimpleResponse struct {
JrebelBaseResponse
StatusCode string `json:"statusCode"`
}



func NewDefaultBaseJsonResponse() JrebelBaseResponse {
return JrebelBaseResponse{
ServerVersion:"3.3.2",
ServerProtocolVersion:"1.1",
ServerGuid:"267b59c9-879a-4c37-9a67-c6d0a8eb3c5d",
GroupType:"managed",
}
}

func NewDefaultLeaseBaseDto() JrebelBaseDto {
return JrebelBaseDto{
Id: 0,
LicenseType: 1,
EvaluationLicense: false,

}
}

var prolongationPeriod int64

func main() {

log.SetOutput(os.Stdout)
host := flag.String("host", "0.0.0.0", "bind on host")
flag.Int64Var(&prolongationPeriod, "prolongationPeriod", 607875500, "prolong ation period")
port := flag.Int("port", 22508, "port number")
addressAndPort := *host + ":"+ strconv.Itoa(*port)
log.Println("*************************************************************")
log.Println("** Jrebel And Jetbrains License Server **")
log.Println("** Jetbrains MyBatis Plugin active host **")
log.Println("** host:x.x.x.x www.codesmagic.com nginx reverse proxy"+strconv.Itoa(*port)+"**")
log.Println("** by: luamas **")
log.Println("** http://www.luamas.com **")
log.Println("** Alipay donation: myluamas@gmail.com **")
log.Println("** Please support genuine!!! **")
log.Println("** You can use --help get the list of arguments **")
log.Println("** listen on "+addressAndPort+" **")
if *host=="0.0.0.0" {
log.Println("** You can use http://127.0.0.1"+strconv.Itoa(*port)+" as license server **")
} else {
log.Println("** You can use http://"+addressAndPort+" as license server **")
}
log.Println("*************************************************************")
if strings.Contains(addressAndPort, "0.0.0.0") {
addressAndPort = strings.Replace(addressAndPort, "0.0.0.0", "", 1)
}
routerBinding()
err := http.ListenAndServe(addressAndPort, http.DefaultServeMux)
if err != nil {
log.Fatalln(err)
}
}

func routerBinding() {
mux := http.NewServeMux()
http.Handle("/", urlMatcher(mux))
}

func urlMatcher(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = strings.ToLower(r.URL.Path)
if r.URL.Path == "/" {
index(w, r)
return
}
isJrebel, err1 := regexp.MatchString("/agent/leases.*", r.URL.Path)
if err1 == nil && isJrebel {
jrebel(w, r)
return
}
isJetbrains, err2 := regexp.MatchString("/rpc/.*\\.action", r.URL.Path)
if err2 == nil && isJetbrains {
jetbrains(w, r)
return
}
isJetbrainsMybatis, err2 := regexp.MatchString("/activate", r.URL.Path)
if err2 == nil && isJetbrainsMybatis {
jetbrainsMybatis(w, r)
return
}
http.Error(w, "页面未找到",404)
})
}


func index(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("License Server"))
}


func jrebel(w http.ResponseWriter, r *http.Request) {
if r.Method == "DELETE" {
jsons, _ := json.Marshal(JrebelSimpleResponse{
StatusCode:"SUCCESS",
JrebelBaseResponse:NewDefaultBaseJsonResponse(),
})
w.Header().Add("Content-Type", "application/json")
w.Write([]byte(jsons))
return
}
guid := r.FormValue("guid")
randomness := r.FormValue("randomness")
username := r.FormValue("username")
offline ,_ := strconv.ParseBool((r.FormValue("offline")))
if guid == "" || randomness == "" || username== "" {
jsons, _ := json.Marshal(JrebelSimpleResponse{
StatusCode:"REBEL_CLIENT_CONFIRMED",
JrebelBaseResponse:NewDefaultBaseJsonResponse(),
})
w.Header().Add("Content-Type", "application/json")
w.Write([]byte(jsons))
return
}
serverRandomness := "wbyUiYWf7Zg="
var validFrom int64
var validUntil int64
var signatureStr string
if offline {
validFrom = time.Now().UnixNano()/1e6
offlineDays , _ := strconv.ParseInt(r.FormValue("offlineDays"),10,64)
validUntil = validFrom + offlineDays*24*60*60*1000
signatureStr = randomness+";"+serverRandomness+";"+guid+";"+strconv.FormatBool(offline)+";"+strconv.FormatInt(int64(validFrom),10)+";"+strconv.FormatInt(int64(validUntil),10)
} else {
signatureStr = randomness+";"+serverRandomness+";"+guid+";"+strconv.FormatBool(offline)
}
signature, _ := leasesSignature(signatureStr)
jsons, _ := json.Marshal(JrebelCreateDto{
JrebelBaseDto:JrebelBaseDto{
JrebelBaseResponse:NewDefaultBaseJsonResponse(),
Id:1,
LicenseType:1,
EvaluationLicense:false,
Signature:signature,
ServerRandomness:serverRandomness,
SeatPoolType:"rebelsuite",
},
StatusCode:"SUCCESS",
Offline:offline,
ValidFrom: validFrom,
ValidUntil: validUntil,
Company:username,
OrderId:"",
ZeroIds: [] string{"JRebel","XRebel","JRebelForAndroid"},
LicenseValidFrom:1491321801000,
LicenseValidUntil:19081501396000,

})

w.Header().Add("Content-Type", "application/json")
w.Write([]byte(jsons))
}

var leasesPrivateKey = []byte(`
-----BEGIN PRIVATE KEY-----
MIICXAIBAAKBgQDQ93CP6SjEneDizCF1P/MaBGf582voNNFcu8oMhgdTZ/N6qa6
O7XJDr1FSCyaDdKSsPCdxPK7Y4Usq/fOPas2kCgYcRS/iebrtPEFZ/7TLfk39HL
uTEjzo0/CNvjVsgWeh9BYznFaxFDLx7fLKqCQ6w1OKScnsdqwjpaXwXqiulwIDA
QABAoGATOQvvBSMVsTNQkbgrNcqKdGjPNrwQtJkk13aO/95ZJxkgCc9vwPqPrOd
FbZappZeHa5IyScOI2nLEfe+DnC7V80K2dBtaIQjOeZQt5HoTRG4EHQaWoDh27B
WuJoip5WMrOd+1qfkOtZoRjNcHl86LIAh/+3vxYyebkug4UHNGPkCQQD+N4ZUkh
KNQW7mpxX6eecitmOdN7Yt0YH9UmxPiW1LyCEbLwduMR2tfyGfrbZALiGzlKJiz
e38shGC1qYSMvZFAkEA0m6psWWiTUWtaOKMxkTkcUdigalZ9xFSEl6jXFB94AD+
dlPS3J5gNzTEmbPLc14VIWJFkO+UOrpl77w5uF2dKwJAaMpslhnsicvKMkv31Ft
But5iK6GWeEafhdPfD94/bnidpP362yJl8Gmya4cI1GXvwH3pfj8S9hJVA5EFvg
TB3QJBAJP1O1uAGp46X7Nfl5vQ1M7RYnHIoXkWtJ417Kb78YWPLVwFlD2LHhuy/
okT4fk8LZ9LeZ5u1cp1RTdLIUqAiAECQC46OwOm87L35yaVfpUIjqg/1gsNwNsj
8HvtXdF/9d30JIM3GwdytCvNRLqP35Ciogb9AO8ke8L6zY83nxPbClM=
-----END PRIVATE KEY-----
`)

func leasesSignature(message string) (string, error) {
pem, _ := pem.Decode(leasesPrivateKey)
rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pem.Bytes)
hashedMessage := sha1.Sum([]byte(message))
signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, crypto.SHA1, hashedMessage[:])
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), nil
}



type JetbrainBaseResponse struct {
ResponseCode string `xml:"responseCode"`
Message string `xml:"message"`
Salt string `xml:"salt"`
}

type PingResponse struct {
JetbrainBaseResponse
}

type ObtainTicketResponse struct {
JetbrainBaseResponse
ProlongationPeriod int64 `xml:"prolongationPeriod"`
TicketId string `xml:"ticketId"`
TicketProperties string `xml:"ticketProperties"`
}

type ProlongTicketResponse struct {
JetbrainBaseResponse
ProlongationPeriod int64 `xml:"prolongationPeriod"`
TicketId string `xml:"ticketId"`
}

type ReleaseTicketResponse struct {
JetbrainBaseResponse
}


func jetbrains(w http.ResponseWriter, r *http.Request) {
salt := r.FormValue("salt")
jetbrainBaseResponse := JetbrainBaseResponse{
ResponseCode:"OK",
Salt: salt,
}
var xmlResponse string
isPing, err1 := regexp.MatchString("/rpc/ping.*", r.URL.Path)
if err1 == nil && isPing {
xmls, _ := xml.Marshal(PingResponse{
JetbrainBaseResponse:jetbrainBaseResponse,
})
xmlResponse = string(xmls)
}

isObtainTicket, err2 := regexp.MatchString("/rpc/obtainticket.action", r.URL.Path)
if err2 == nil && isObtainTicket {
username := r.FormValue("userName")
xmls, _ := xml.Marshal(ObtainTicketResponse{
JetbrainBaseResponse:jetbrainBaseResponse,
TicketId: "1",
ProlongationPeriod:prolongationPeriod,
TicketProperties: "licensee=" + username + " licenseType=0 ",
})
xmlResponse = string(xmls)
}

isProlongTicket, err3 := regexp.MatchString("/rpc/prolongticket.*", r.URL.Path)
if err3 == nil && isProlongTicket {
ticketId := r.FormValue("ticketId")
xmls, _ := xml.Marshal(ProlongTicketResponse{
JetbrainBaseResponse:jetbrainBaseResponse,
ProlongationPeriod:prolongationPeriod,
TicketId: ticketId,
})
xmlResponse = string(xmls)
}

isReleaseTicket, err4 := regexp.MatchString("/rpc/releaseticket.*", r.URL.Path)
if err4 == nil && isReleaseTicket {
xmls, _ := xml.Marshal(ReleaseTicketResponse{
JetbrainBaseResponse:jetbrainBaseResponse,
})
xmlResponse = string(xmls)
}

xmlSignature, _ := jetbrainsignature(xmlResponse)

w.Header().Add("Content-Type", "text/xml")
w.Write([]byte("<!-- " + xmlSignature + " -->\n" + xmlResponse))
}

var jetbrainprivateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALecq3BwAI4YJZwhJ+snnDFj3lF3DMqNPorV6y5ZKXCiCMqj8OeOmxk4YZW9aaV9
ckl/zlAOI0mpB3pDT+Xlj2sCAwEAAQJAW6/aVD05qbsZHMvZuS2Aa5FpNNj0BDlf38hOtkhDzz/h
kYb+EBYLLvldhgsD0OvRNy8yhz7EjaUqLCB0juIN4QIhAOeCQp+NXxfBmfdG/S+XbRUAdv8iHBl+
F6O2wr5fA2jzAiEAywlDfGIl6acnakPrmJE0IL8qvuO3FtsHBrpkUuOnXakCIQCqdr+XvADI/UTh
TuQepuErFayJMBSAsNe3NFsw0cUxAQIgGA5n7ZPfdBi3BdM4VeJWb87WrLlkVxPqeDSbcGrCyMkC
IFSs5JyXvFTreWt7IQjDssrKDRIPmALdNjvfETwlNJyY
-----END RSA PRIVATE KEY-----
`)

func jetbrainsignature(message string) (string, error) {
pem, _ := pem.Decode(jetbrainprivateKey)
rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pem.Bytes)

hashedMessage := md5.Sum([]byte(message))
signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, crypto.MD5, hashedMessage[:])
if err != nil {
return "", err
}
hexSignature := hex.EncodeToString(signature)
return hexSignature, nil
}


func jetbrainsMybatis(w http.ResponseWriter, r *http.Request) {
json := "{\"verified\":true,\"message\":\"Activation success\",\"key\":\"30820122300d06092a864886f70d01010105000382010f003082010a02820101008e5fae9b71952c2715dba9fb9cd5f13eaf47f4175acd03bca61f39b30f73e3d6d9f80a4d2600cfdee0d9f78800bbd71ae9d07d380136c1edd853a4022454641d98e52f6e5bbff866ed8a75bf05bfe4b45d8280715611a1bf92c8fc907f98f25c66559796814928b7e63cf3d61c4a096648ddd967f47b31c972d690a41a3737bb30e500057aebc256346120b322e19ccd4c2a5cbc6cf6092ccbbde107bacf2a9efe2aaa435bba5e672ed7d44447818846ab7ca6a3bc3e7480aa0936c72ea353266627063cbd7886aa99aaa1e798ef7b59777fdd7ae20c686ac2fba37269b7e56e12bd281af02e240af1ea110d226da4340111384796b6b945f936df6a37994c5b0203010001\",\"result\":\"4b59bca03a48ee797f312509d4d4bbe0e5e8f4a83890e3b12152ad93f26e0b9127293050ede126f05cb26f4f3f40fc6c83a056013d347aeff7d01e411954175cf4e30d7e45b6edd625083bf4cc18c515c9b26e264001f7d90ab2f35ad05b7b6cf15a8212372370344ec03289f50b520ea125da3e1bf4fe5eb11a00b043ec352ec19eebbb203c29978066e293adb6b9781d8ef72247f0dbdbf7df98e314b915f750832cc1e7eee108ea1759437ba36ada428ebdb864bbba495f9a3e6f5544b04e301cfc8004ae7b373f61367bbc967ac23fd4272b001f48e63725e2f35907e2134e5f56e034324dce90889374d7db1f1f02913abf55758be79a62d6ca7f6be4e0\"}"
w.Header().Add("Content-Type", "application/json")
w.Write([]byte(json))
}

+ 7
- 0
run.sh View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash

docker rm -f license-server
docker build --rm=true -t luamas/license-server:latest --file Dockerfile .
docker run --restart=always \
-p 22508:22508 \
--name license-server -d luamas/license-server

Loading…
Cancel
Save