working commit
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
package auxgin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CorsMiddleware() gin.HandlerFunc {
|
||||
|
||||
headers := []string{"Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"}
|
||||
headerList := strings.Join(headers, ",")
|
||||
|
||||
methods := []string{"POST", "GET", "OPTIONS", "PUT", "DELETE", "UPDATE"}
|
||||
methodList := strings.Join(methods, ",")
|
||||
|
||||
return func(gctx *gin.Context) {
|
||||
gctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
gctx.Writer.Header().Set("Access-Control-Max-Age", "86400")
|
||||
gctx.Writer.Header().Set("Access-Control-Allow-Methods", methodList)
|
||||
gctx.Writer.Header().Set("Access-Control-Allow-Headers", headerList)
|
||||
gctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
|
||||
if gctx.Request.Method == "OPTIONS" {
|
||||
gctx.AbortWithStatus(http.StatusOK)
|
||||
} else {
|
||||
gctx.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package auxgin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func LogMiddleware() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
ctx.Next()
|
||||
|
||||
var reqSize int64
|
||||
var method string
|
||||
var reqURI string
|
||||
var remAddr string
|
||||
if ctx.Request != nil {
|
||||
reqSize = ctx.Request.ContentLength
|
||||
method = ctx.Request.Method
|
||||
reqURI = ctx.Request.RequestURI
|
||||
remAddr = ctx.RemoteIP()
|
||||
}
|
||||
|
||||
duration := time.Since(start).Microseconds()
|
||||
|
||||
var resCode int
|
||||
var resSize int
|
||||
if ctx.Writer != nil {
|
||||
resCode = ctx.Writer.Status()
|
||||
resSize = ctx.Writer.Size()
|
||||
}
|
||||
|
||||
logString := fmt.Sprintf("%s %s %s in=%d out=%d res=%d %dms",
|
||||
remAddr, method, reqURI, reqSize, resSize, resCode, duration)
|
||||
|
||||
logger := logrus.WithField("object", "accesslog")
|
||||
logger.Infoln(logString)
|
||||
}
|
||||
}
|
||||
|
||||
type LogWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
func (lw LogWriter) Write(data []byte) (int, error) {
|
||||
lw.body.Write(data)
|
||||
return lw.ResponseWriter.Write(data)
|
||||
}
|
||||
|
||||
func (lw LogWriter) WriteString(data string) (int, error) {
|
||||
lw.body.WriteString(data)
|
||||
return lw.ResponseWriter.WriteString(data)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package auxgin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func RequestLogMiddleware() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
|
||||
contentType := context.GetHeader("Content-Type")
|
||||
contentType = strings.ToLower(contentType)
|
||||
|
||||
var requestBody []byte
|
||||
if context.Request.Body != nil {
|
||||
requestBody, _ = ioutil.ReadAll(context.Request.Body)
|
||||
}
|
||||
|
||||
if strings.Contains(contentType, "application/json") && context.Request.Method == "POST" {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
json.Indent(buffer, requestBody, "", " ")
|
||||
logger := logrus.WithField("object", "requestlog")
|
||||
logger.Infoln("request:\n", buffer.String())
|
||||
}
|
||||
|
||||
context.Request.Body = ioutil.NopCloser(bytes.NewReader(requestBody))
|
||||
context.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package auxgin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ResponseLogMiddleware() gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
contentType := context.GetHeader("Content-Type")
|
||||
contentType = strings.ToLower(contentType)
|
||||
|
||||
writer := &LogWriter{
|
||||
body: bytes.NewBuffer(nil),
|
||||
ResponseWriter: context.Writer,
|
||||
}
|
||||
context.Writer = writer
|
||||
|
||||
context.Next()
|
||||
|
||||
if strings.Contains(contentType, "application/json") {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
json.Indent(buffer, writer.body.Bytes(), "", " ")
|
||||
logger := logrus.WithField("object", "responselog")
|
||||
logger.Infoln("request:\n", buffer.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||
*/
|
||||
package auxuuid
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const ZeroUUID string = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
func NewUUID() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package common
|
||||
@@ -0,0 +1,34 @@
|
||||
package descr
|
||||
|
||||
const (
|
||||
GrantModifyUsers = "modifyUsers"
|
||||
GrantModifyDatabase = "modifyDatabase"
|
||||
)
|
||||
|
||||
type Dump struct {
|
||||
Timestamp string `json:"timestamp" yaml:"timestamp"`
|
||||
Accounts []Account `json:"accounts" yaml:"accounts"`
|
||||
Grants []Grant `json:"grants" yaml:"grants"`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
ID string `json:"id" yaml:"id" db:"id"`
|
||||
Username string `json:"username" yaml:"username" db:"username"`
|
||||
Passhash string `json:"passhash" yaml:"passhash" db:"passhash"`
|
||||
Disabled bool `json:"disabled" yaml:"disabled" db:"disabled"`
|
||||
CreatedAt string `json:"createdAt" yaml:"createdAt" db:"created_at"`
|
||||
UpdatedAt string `json:"updatedAt" yaml:"updatedAt" db:"updated_at"`
|
||||
}
|
||||
|
||||
type Grant struct {
|
||||
ID string `json:"id" yaml:"id" db:"id"`
|
||||
AccountID string `json:"accountID" yaml:"accountID" db:"account_id"`
|
||||
Operation string `json:"operation" yaml:"operation" db:"operation"`
|
||||
CreatedAt string `json:"createdAt" yaml:"createdAt" db:"created_at"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
DatabaseInitialized bool `json:"databaseInitialized" yaml:"databaseInitialized"`
|
||||
CreatedAt string `json:"createdAt" yaml:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt" yaml:"updatedAt"`
|
||||
}
|
||||
+24
-24
@@ -192,7 +192,7 @@ func (*RestoreDumpResult) Descriptor() ([]byte, []int) {
|
||||
type SetGrantParams struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -235,11 +235,11 @@ func (x *SetGrantParams) GetUsername() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetGrantParams) GetAccountID() int64 {
|
||||
func (x *SetGrantParams) GetAccountID() string {
|
||||
if x != nil {
|
||||
return x.AccountID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetGrantParams) GetOperation() string {
|
||||
@@ -251,7 +251,7 @@ func (x *SetGrantParams) GetOperation() string {
|
||||
|
||||
type SetGrantResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
GrantID int64 `protobuf:"varint,1,opt,name=grantID,proto3" json:"grantID,omitempty"`
|
||||
GrantID string `protobuf:"bytes,1,opt,name=grantID,proto3" json:"grantID,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -286,17 +286,17 @@ func (*SetGrantResult) Descriptor() ([]byte, []int) {
|
||||
return file_mbctl_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *SetGrantResult) GetGrantID() int64 {
|
||||
func (x *SetGrantResult) GetGrantID() string {
|
||||
if x != nil {
|
||||
return x.GrantID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteGrantParams struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -339,11 +339,11 @@ func (x *DeleteGrantParams) GetUsername() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DeleteGrantParams) GetAccountID() int64 {
|
||||
func (x *DeleteGrantParams) GetAccountID() string {
|
||||
if x != nil {
|
||||
return x.AccountID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DeleteGrantParams) GetOperation() string {
|
||||
@@ -443,7 +443,7 @@ func (x *CreateAccountParams) GetPassword() string {
|
||||
|
||||
type CreateAccountResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
AccountID int64 `protobuf:"varint,1,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
AccountID string `protobuf:"bytes,1,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -478,17 +478,17 @@ func (*CreateAccountResult) Descriptor() ([]byte, []int) {
|
||||
return file_mbctl_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *CreateAccountResult) GetAccountID() int64 {
|
||||
func (x *CreateAccountResult) GetAccountID() string {
|
||||
if x != nil {
|
||||
return x.AccountID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteAccountParams struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -530,11 +530,11 @@ func (x *DeleteAccountParams) GetUsername() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DeleteAccountParams) GetAccountID() int64 {
|
||||
func (x *DeleteAccountParams) GetAccountID() string {
|
||||
if x != nil {
|
||||
return x.AccountID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteAccountResult struct {
|
||||
@@ -576,7 +576,7 @@ func (*DeleteAccountResult) Descriptor() ([]byte, []int) {
|
||||
type UpdateAccountParams struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"`
|
||||
NewUsername string `protobuf:"bytes,3,opt,name=newUsername,proto3" json:"newUsername,omitempty"`
|
||||
NewPassword string `protobuf:"bytes,4,opt,name=newPassword,proto3" json:"newPassword,omitempty"`
|
||||
Disabled bool `protobuf:"varint,5,opt,name=disabled,proto3" json:"disabled,omitempty"`
|
||||
@@ -621,11 +621,11 @@ func (x *UpdateAccountParams) GetUsername() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateAccountParams) GetAccountID() int64 {
|
||||
func (x *UpdateAccountParams) GetAccountID() string {
|
||||
if x != nil {
|
||||
return x.AccountID
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UpdateAccountParams) GetNewUsername() string {
|
||||
@@ -1063,17 +1063,17 @@ var file_mbctl_proto_rawDesc = string([]byte{
|
||||
0x65, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2a, 0x0a, 0x0e, 0x73, 0x65, 0x74, 0x47, 0x72, 0x61, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74,
|
||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49,
|
||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49,
|
||||
0x44, 0x22, 0x6b, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74,
|
||||
0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44,
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x13,
|
||||
0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
||||
@@ -1084,19 +1084,19 @@ var file_mbctl_proto_rawDesc = string([]byte{
|
||||
0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
|
||||
0x72, 0x64, 0x22, 0x33, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x4f, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61,
|
||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65,
|
||||
0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
|
||||
0xaf, 0x01, 0x0a, 0x13, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49,
|
||||
0x44, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
|
||||
|
||||
Reference in New Issue
Block a user