1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-09-13 07:13:00 +03:00

JSON-RPC CodeGen Developer Tool

This commit is contained in:
Daiyuu Nobori 2019-05-28 11:38:38 +09:00
parent a3c29fbca6
commit d63f637253
16 changed files with 14034 additions and 0 deletions

View File

@ -0,0 +1,350 @@
# Created by https://www.gitignore.io/api/visualstudio
# Edit at https://www.gitignore.io/?templates=visualstudio
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# End of https://www.gitignore.io/api/visualstudio

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Diagnostics;
using Newtonsoft.Json;
using SoftEther.VPNServerRpc;
using System.Text;
using SoftEther.JsonRpc;
namespace VPNServer_JSONRPC_CodeGen
{
class Program
{
static void Main(string[] args)
{
string output_dir = CodeGenUtil.OutputDir_Clients;
try
{
Directory.CreateDirectory(output_dir);
}
catch
{
}
CodeGen g = new CodeGen();
g.GenerateAndSaveCodes(output_dir);
}
}
}

View File

@ -0,0 +1,17 @@
// SoftEther VPN Server JSON-RPC Stub code for C#
//
// Program.cs - The Main() entry point
//
// Automatically generated at __TIMESTAMP__ by vpnserver-jsonrpc-codegen
//
// Licensed under the Apache License 2.0
// Copyright (c) 2014-__YEAR__ SoftEther VPN Project
class Program
{
static void Main(string[] args)
{
VPNRPCTest test = new VPNRPCTest();
test.Test_All();
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>SoftEther.VPNServerRpc</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2041
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vpnserver-jsonrpc-client-csharp", "vpnserver-jsonrpc-client-csharp.csproj", "{81CA3EC4-026E-4D37-9889-828186BBB8C0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{81CA3EC4-026E-4D37-9889-828186BBB8C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81CA3EC4-026E-4D37-9889-828186BBB8C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81CA3EC4-026E-4D37-9889-828186BBB8C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81CA3EC4-026E-4D37-9889-828186BBB8C0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D87E5CF1-9A10-431C-AC42-F1041470AEE8}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,34 @@
# SoftEther VPN Server JSON-RPC Document
This reference describes all JSON-RPC functions available on SoftEther VPN Server.
Please note that you can use [SoftEther VPN Server JSON-RPC Client Library](https://github.com/SoftEtherVPN/SoftEtherVPN/tree/master/developer_tools/vpnserver-jsonrpc-clients/) to call these APIs easily instead of calling JSON through HTTPS.
## Principle
### Entry point
The entry point URL of JSON-RPC is:
```
https://<vpn_server_hostname>:<port>/api/
```
### JSON-RPC specification
You must use HTTPS 1.1 `POST` method to call each of JSON-RPC APIs.
All APIs are based on the [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification).
- JSON-RPC Notification is not supported.
- JSON-RPC Batch is not supported.
### Authentication
You must specify the following HTTPS custom headers for authentication on each of requests.
Value | Description
--- | ---
`X-VPNADMIN-HUBNAME` | The name of the Virtual Hub if you want to connect to the VPN Server as a Virtual Hub Admin Mode. Specify empty string if you want to connect to the VPN Server as the Entire VPN Server Admin Mode.
`X-VPNADMIN-PASSWORD` | Specify the administration password.
- You can omit the above HTTPS custom authentication headers if you are calling JSON-RPC APIs from the web browser which is already logged in to the VPN Server with HTTPS Basic Authentication. In such usage the credential of HTTPS Basic Authtication will be used.
***

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>SoftEther VPN Server JSON-RPC Document</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/2.10.0/github-markdown.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/themes/prism.css">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/components/prism-json.js"></script>
<article class="markdown-body">
__BODY__
</article>
</body>
</html>

View File

@ -0,0 +1,576 @@
// SoftEther VPN Server JSON-RPC Stub code for TypeScript
//
// vpnrpc.ts
// Automatically generated at __TIMESTAMP__ by vpnserver-jsonrpc-codegen
//
// Licensed under the Apache License 2.0
// Copyright (c) 2014-__YEAR__ SoftEther VPN Project
// Trivial utility codes
let is_node_js = (typeof navigator === "undefined") || navigator.userAgent.indexOf("Node.js") !== -1 || navigator.userAgent.indexOf("jsdom") !== -1;
function is_null(obj: any)
{
return (typeof obj === "undefined") || (obj === null);
}
let debug_mode: boolean = false;
/** VPN Server RPC Stubs */
export class VpnServerRpc
{
/** Determine if this JavaScript environment is on the Node.js or not. */
public static IsNodeJS(): boolean
{
return is_node_js;
}
/** Set the debug mode flag */
public static SetDebugMode(flag: boolean): void
{
debug_mode = flag;
}
private rpc_url: string;
private rpc_client: JsonRpcClient;
/**
* Constructor of the VpnServerRpc class
* @param vpnserver_hostname The hostname or IP address of the destination VPN Server. In the web browser you can specify null if you want to connect to the server itself.
* @param vpnserver_port The port number of the destination VPN Server. In the web browser you can specify null if you want to connect to the server itself.
* @param hubname The name of the Virtual Hub if you want to connect to the VPN Server as a Virtual Hub Admin Mode. Specify null if you want to connect to the VPN Server as the Entire VPN Server Admin Mode.
* @param password Specify the administration password. This value is valid only if vpnserver_hostname is sepcified.
* @param nodejs_https_client_reject_untrusted_server_cert In Node.js set this true to check the SSL server certificate on the destination VPN Server. Set this false to ignore the SSL server certification.
*/
constructor(vpnserver_hostname?: string, vpnserver_port?: number, hubname?: string, password?: string, nodejs_https_client_reject_untrusted_server_cert?: boolean)
{
let headers: { [name: string]: string } = {};
let send_credentials: boolean = false;
nodejs_https_client_reject_untrusted_server_cert = is_null(nodejs_https_client_reject_untrusted_server_cert) ? false : nodejs_https_client_reject_untrusted_server_cert!;
if (is_null(vpnserver_hostname))
{
this.rpc_url = "/api/";
send_credentials = true;
}
else
{
if (is_null(vpnserver_port)) vpnserver_port = 443;
this.rpc_url = `https://${vpnserver_hostname}:${vpnserver_port}/api/`;
headers["X-VPNADMIN-HUBNAME"] = is_null(hubname) ? "" : hubname!;
headers["X-VPNADMIN-PASSWORD"] = is_null(password) ? "" : password!;
}
if (is_null(nodejs_https_client_reject_untrusted_server_cert)) nodejs_https_client_reject_untrusted_server_cert = false;
this.rpc_client = new JsonRpcClient(this.rpc_url, headers, send_credentials, nodejs_https_client_reject_untrusted_server_cert);
}
// --- Stubs ---
__STUBS__
// -- Utility functions --
/** Call a RPC procedure */
public async CallAsync<T>(method_name: string, request: T): Promise<T>
{
let response: T = await this.rpc_client.CallAsync<T>(method_name, request);
return response;
}
}
// --- Types ---
__TYPES__
// --- Utility codes ---
/** JSON-RPC request class. See https://www.jsonrpc.org/specification */
export class JsonRpcRequest
{
public jsonrpc: string = "2.0";
public method: string;
public params: any;
public id: string;
constructor(method: string = "", param: any = null, id: string = "")
{
this.method = method;
this.params = param;
this.id = id;
}
}
/** JSON-RPC error class. See https://www.jsonrpc.org/specification */
export class JsonRpcError
{
public code: number;
public message: string;
public data: any;
constructor(code: number = 0, message: string = "", data: any = null)
{
this.code = code;
this.message = message;
this.data = data;
}
}
/** JSON-RPC response class with generics */
export class JsonRpcResponse<TResult>
{
public jsonrpc: string = "2.0";
public result: TResult = null!;
public error: JsonRpcError = null!;
public id: string = "";
}
/** JSON-RPC client class. See https://www.jsonrpc.org/specification */
export class JsonRpcClient
{
/** A utility function to convert any object to JSON string */
public static ObjectToJson(obj: any): string
{
return JSON.stringify(obj,
(key, value) =>
{
if (key.endsWith("_bin"))
{
return Util_Base64_Encode(value);
}
return value;
}
, 4);
}
/** A utility function to convert JSON string to object */
public static JsonToObject(str: string): any
{
return JSON.parse(str,
(key, value) =>
{
if (key.endsWith("_bin"))
{
return Util_Base64_Decode(value);
}
else if (key.endsWith("_dt"))
{
return new Date(value);
}
return value;
});
}
/** Base URL */
public BaseUrl: string;
/** The instance of HTTP client */
private client: HttpClient;
/** Additional HTTP headers */
private headers: { [name: string]: string };
/**
* JSON-RPC client class constructor
* @param url The URL
* @param headers Additional HTTP headers
* @param send_credential Set true to use the same credential with the browsing web site. Valid only if the code is running on the web browser.
*/
constructor(url: string, headers: { [name: string]: string }, send_credential: boolean, nodejs_https_client_reject_untrusted_server_cert: boolean)
{
this.BaseUrl = url;
this.headers = headers;
this.client = new HttpClient();
this.client.SendCredential = send_credential;
this.client.NodeJS_HTTPS_Client_Reject_Unauthorized = nodejs_https_client_reject_untrusted_server_cert;
}
/**
* Call a single RPC call (without error check). You can wait for the response with Promise<string> or await statement.
* @param method_name The name of RPC method
* @param param The parameters
*/
public async CallInternalAsync(method_name: string, param: any): Promise<string>
{
let id = "1";
let req = new JsonRpcRequest(method_name, param, id);
let req_string = JsonRpcClient.ObjectToJson(req);
if (debug_mode)
{
console.log("--- RPC Request Body ---");
console.log(req_string);
console.log("------------------------");
}
let http_response = await this.client.PostAsync(this.BaseUrl, this.headers,
req_string, "application/json");
let ret_string = http_response.Body;
if (debug_mode)
{
console.log("--- RPC Response Body ---");
console.log(ret_string);
console.log("-------------------------");
}
return ret_string;
}
/**
* Call a single RPC call (with error check). You can wait for the response with Promise<TResult> or await statement. In the case of error, it will be thrown.
* @param method_name The name of RPC method
* @param param The parameters
*/
public async CallAsync<TResult>(method_name: string, param: any): Promise<TResult>
{
let ret_string = await this.CallInternalAsync(method_name, param);
let ret: JsonRpcResponse<TResult> = JSON.parse(ret_string);
if (is_null(ret.error) === false)
{
throw new JsonRpcException(ret.error);
}
return ret.result;
}
}
/** JSON-RPC exception class */
export class JsonRpcException extends Error
{
public Error: JsonRpcError;
constructor(error: JsonRpcError)
{
super(`Code=${error.code}, Message=${error.message}`);
this.Error = error;
}
}
/** HTTP client exception class */
export class HttpClientException extends Error
{
constructor(message: string)
{
super(message);
}
}
/** HTTP client response class */
export class HttpClientResponse
{
public Body: string = "";
}
/** An HTTP client which can be used in both web browsers and Node.js */
export class HttpClient
{
public TimeoutMsecs: number = 60 * 5 * 1000;
public SendCredential: boolean = true;
public NodeJS_HTTPS_Client_Reject_Unauthorized: boolean = false;
/** Post method. In web browsers this function will process the request by itself. In Node.js this function will call PostAsync_NodeJS() instead. */
public async PostAsync(url: string, headers: { [name: string]: string },
req_body: string, req_media_type: string): Promise<HttpClientResponse>
{
if (is_node_js)
{
return this.PostAsync_NodeJS(url, headers, req_body, req_media_type);
}
let fetch_header_list = new Headers();
for (let name of Object.keys(headers))
{
fetch_header_list.append(name, headers[name]);
}
let fetch_init: RequestInit =
{
mode: "cors",
headers: fetch_header_list,
credentials: (this.SendCredential ? "include" : "omit"),
method: "POST",
cache: "no-cache",
keepalive: true,
redirect: "follow",
body: req_body,
};
let fetch_response = await fetch(url, fetch_init);
if (fetch_response.ok === false)
{
throw new HttpClientException("HTTP Error: " + fetch_response.status + " " + fetch_response.statusText);
}
let ret = new HttpClientResponse();
ret.Body = await fetch_response.text();
return ret;
}
/** Post method for Node.js. */
public PostAsync_NodeJS(url: string, headers: { [name: string]: string },
req_body: string, req_media_type: string): Promise<HttpClientResponse>
{
const https = require("https");
const keepAliveAgent = new https.Agent({ keepAlive: true });
const urlparse = require("url");
const urlobj = urlparse.parse(url);
if (is_null(urlobj.host)) throw new Error("URL is invalid.");
let options =
{
host: urlobj.hostname,
port: urlobj.port,
path: urlobj.path,
rejectUnauthorized: this.NodeJS_HTTPS_Client_Reject_Unauthorized,
method: "POST",
timeout: this.TimeoutMsecs,
agent: keepAliveAgent,
};
return new Promise(function (resolve, reject)
{
let req = https.request(options, (res: any) =>
{
if (res.statusCode !== 200)
{
reject(new HttpClientException("HTTP Error: " + res.statusCode + " " + res.statusMessage));
}
let recv_str: string = "";
res.on("data", (body: any) =>
{
recv_str += body;
});
res.on("end", () =>
{
let ret = new HttpClientResponse();
ret.Body = recv_str;
resolve(ret);
});
}).on("error", (err: any) =>
{
throw err;
}
);
for (let name of Object.keys(headers))
{
req.setHeader(name, !is_null(headers[name]) ? headers[name] : "");
}
req.setHeader("Content-Type", req_media_type);
req.setHeader("Content-Length", Buffer.byteLength(req_body));
req.write(req_body);
req.end();
});
}
}
//////// BEGIN: Base64 encode / decode utility functions from https://github.com/beatgammit/base64-js
// The MIT License(MIT)
// Copyright(c) 2014
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
var lookup: any = [];
var revLookup: any = [];
var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var i = 0, len = code.length; i < len; ++i)
{
lookup[i] = code[i];
revLookup[code.charCodeAt(i)] = i;
}
// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup["-".charCodeAt(0)] = 62;
revLookup["_".charCodeAt(0)] = 63;
function getLens(b64: any)
{
var len = b64.length;
if (len % 4 > 0)
{
throw new Error("Invalid string. Length must be a multiple of 4");
}
// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
var validLen = b64.indexOf("=");
if (validLen === -1) validLen = len;
var placeHoldersLen = validLen === len
? 0
: 4 - (validLen % 4);
return [validLen, placeHoldersLen];
}
// base64 is 4/3 + up to two characters of the original data
function byteLength(b64: any)
{
var lens = getLens(b64);
var validLen = lens[0];
var placeHoldersLen = lens[1];
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
}
function _byteLength(b64: any, validLen: any, placeHoldersLen: any)
{
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
}
export function Util_Base64_Decode(b64: any)
{
var tmp;
var lens = getLens(b64);
var validLen = lens[0];
var placeHoldersLen = lens[1];
var arr = new Uint8Array(_byteLength(b64, validLen, placeHoldersLen));
var curByte = 0;
// if there are placeholders, only get up to the last complete 4 chars
var len = placeHoldersLen > 0
? validLen - 4
: validLen;
for (var i = 0; i < len; i += 4)
{
tmp =
(revLookup[b64.charCodeAt(i)] << 18) |
(revLookup[b64.charCodeAt(i + 1)] << 12) |
(revLookup[b64.charCodeAt(i + 2)] << 6) |
revLookup[b64.charCodeAt(i + 3)];
arr[curByte++] = (tmp >> 16) & 0xFF;
arr[curByte++] = (tmp >> 8) & 0xFF;
arr[curByte++] = tmp & 0xFF;
}
if (placeHoldersLen === 2)
{
tmp =
(revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4);
arr[curByte++] = tmp & 0xFF;
}
if (placeHoldersLen === 1)
{
tmp =
(revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2);
arr[curByte++] = (tmp >> 8) & 0xFF;
arr[curByte++] = tmp & 0xFF;
}
return arr;
}
function tripletToBase64(num: any)
{
return lookup[num >> 18 & 0x3F] +
lookup[num >> 12 & 0x3F] +
lookup[num >> 6 & 0x3F] +
lookup[num & 0x3F];
}
function encodeChunk(uint8: any, start: any, end: any)
{
var tmp;
var output = [];
for (var i = start; i < end; i += 3)
{
tmp =
((uint8[i] << 16) & 0xFF0000) +
((uint8[i + 1] << 8) & 0xFF00) +
(uint8[i + 2] & 0xFF);
output.push(tripletToBase64(tmp));
}
return output.join("");
}
export function Util_Base64_Encode(uint8: any)
{
var tmp;
var len = uint8.length;
var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
var parts = [];
var maxChunkLength = 16383; // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength)
{
parts.push(encodeChunk(
uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
));
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1)
{
tmp = uint8[len - 1];
parts.push(
lookup[tmp >> 2] +
lookup[(tmp << 4) & 0x3F] +
"=="
);
} else if (extraBytes === 2)
{
tmp = (uint8[len - 2] << 8) + uint8[len - 1];
parts.push(
lookup[tmp >> 10] +
lookup[(tmp >> 4) & 0x3F] +
lookup[(tmp << 2) & 0x3F] +
"="
);
}
return parts.join("");
}
//////// END: Base64 encode / decode utility functions from https://github.com/beatgammit/base64-js

View File

@ -0,0 +1,48 @@
// Test sample code for SoftEther VPN Server JSON-RPC Stub
// Runs on both web browsers and Node.js
//
// sample.ts
// Automatically generated at __TIMESTAMP__ by vpnserver-jsonrpc-codegen
//
// This sample code shows how to call all available RPC functions.
// You can copy and paste test code to write your own web browser TypeScript / JavaScript codes.
//
// Licensed under the Apache License 2.0
// Copyright (c) 2014-__YEAR__ SoftEther VPN Project
// On the web browser uncomment below imports as necessary to support old browsers.
// import "core-js/es6/promise";
// import "core-js/es6/string";
// import "whatwg-fetch";
// Import the vpnrpc.ts RPC stub.
import * as VPN from "./vpnrpc";
// Output JSON-RPC request / reply strings to the debug console.
VPN.VpnServerRpc.SetDebugMode(true);
let api: VPN.VpnServerRpc;
// Creating the VpnServerRpc class instance here.
if (VPN.VpnServerRpc.IsNodeJS() === false) // // Determine if this JavaScript environment is on the Node.js or not
{
// On the web browser. We do not need to specify any hostname, port or credential as the web browser already knows it.
api = new VPN.VpnServerRpc();
}
else
{
// On the Node.js. We need to specify the target VPN Server's hostname, port and credential.
api = new VPN.VpnServerRpc("127.0.0.1", 443, "", "PASSWORD_HERE", false);
}
// A variable for test
let hub_name = "test";
// Call the Test_All() function to test almost all VPN APIs.
Test_All();
__TESTS__

View File

@ -0,0 +1,282 @@
// SoftEther VPN Server JSON-RPC Stub code for C#
//
// JsonRpc.cs - JSON-RPC Client Utility Functions
//
// Automatically generated at __TIMESTAMP__ by vpnserver-jsonrpc-codegen
//
// Licensed under the Apache License 2.0
// Copyright (c) 2014-__YEAR__ SoftEther VPN Project
using System;
using System.IO;
using System.Net.Security;
using System.Net.Http;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SoftEther.JsonRpc
{
/// <summary>
/// Internal utility class
/// </summary>
static class ClientUtil
{
public const int DefaultMaxDepth = 8;
public static string NonNull(this string s) { if (s == null) return ""; else return s; }
public static bool IsEmpty(this string str)
{
if (str == null || str.Trim().Length == 0)
return true;
else
return false;
}
public static bool IsFilled(this string str) => !IsEmpty(str);
public static string ObjectToJson(this object obj, bool include_null = false, bool escape_html = false, int? max_depth = ClientUtil.DefaultMaxDepth, bool compact = false, bool reference_handling = false) => ClientUtil.Serialize(obj, include_null, escape_html, max_depth, compact, reference_handling);
public static T JsonToObject<T>(this string str, bool include_null = false, int? max_depth = ClientUtil.DefaultMaxDepth) => ClientUtil.Deserialize<T>(str, include_null, max_depth);
public static object JsonToObject(this string str, Type type, bool include_null = false, int? max_depth = ClientUtil.DefaultMaxDepth) => ClientUtil.Deserialize(str, type, include_null, max_depth);
public static string Serialize(object obj, bool include_null = false, bool escape_html = false, int? max_depth = ClientUtil.DefaultMaxDepth, bool compact = false, bool reference_handling = false)
{
JsonSerializerSettings setting = new JsonSerializerSettings()
{
MaxDepth = max_depth,
NullValueHandling = include_null ? NullValueHandling.Include : NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Error,
PreserveReferencesHandling = reference_handling ? PreserveReferencesHandling.All : PreserveReferencesHandling.None,
StringEscapeHandling = escape_html ? StringEscapeHandling.EscapeHtml : StringEscapeHandling.Default,
};
return JsonConvert.SerializeObject(obj, compact ? Formatting.None : Formatting.Indented, setting);
}
public static T Deserialize<T>(string str, bool include_null = false, int? max_depth = ClientUtil.DefaultMaxDepth)
=> (T)Deserialize(str, typeof(T), include_null, max_depth);
public static object Deserialize(string str, Type type, bool include_null = false, int? max_depth = ClientUtil.DefaultMaxDepth)
{
JsonSerializerSettings setting = new JsonSerializerSettings()
{
MaxDepth = max_depth,
NullValueHandling = include_null ? NullValueHandling.Include : NullValueHandling.Ignore,
ObjectCreationHandling = ObjectCreationHandling.Replace,
ReferenceLoopHandling = ReferenceLoopHandling.Error,
};
return JsonConvert.DeserializeObject(str, type, setting);
}
public static void Print(this object o)
{
string str = o.ObjectToJson();
if (o is string) str = (string)o;
Console.WriteLine(str);
}
}
/// <summary>
/// JSON-RPC exception class
/// </summary>
class JsonRpcException : Exception
{
public JsonRpcError RpcError { get; }
public JsonRpcException(JsonRpcError err)
: base($"Code={err.Code}, Message={err.Message.NonNull()}" +
(err == null || err.Data == null ? "" : $", Data={err.Data.ObjectToJson(compact: true)}"))
{
this.RpcError = err;
}
}
/// <summary>
/// JSON-RPC request class. See https://www.jsonrpc.org/specification
/// </summary>
class JsonRpcRequest
{
[JsonProperty("jsonrpc", Order = 1)]
public string Version { get; set; } = "2.0";
[JsonProperty("id", Order = 2)]
public string Id { get; set; } = null;
[JsonProperty("method", Order = 3)]
public string Method { get; set; } = "";
[JsonProperty("params", Order = 4)]
public object Params { get; set; } = null;
public JsonRpcRequest() { }
public JsonRpcRequest(string method, object param, string id)
{
this.Method = method;
this.Params = param;
this.Id = id;
}
}
/// <summary>
/// JSON-RPC response class with generics
/// </summary>
/// <typeparam name="TResult"></typeparam>
class JsonRpcResponse<TResult>
{
[JsonProperty("jsonrpc", Order = 1)]
public virtual string Version { get; set; } = "2.0";
[JsonProperty("id", NullValueHandling = NullValueHandling.Include, Order = 2)]
public virtual string Id { get; set; } = null;
[JsonProperty("result", Order = 3)]
public virtual TResult Result { get; set; } = default(TResult);
[JsonProperty("error", Order = 4)]
public virtual JsonRpcError Error { get; set; } = null;
[JsonIgnore]
public virtual bool IsError => this.Error != null;
[JsonIgnore]
public virtual bool IsOk => !IsError;
public virtual void ThrowIfError()
{
if (this.IsError) throw new JsonRpcException(this.Error);
}
public override string ToString()
{
return this.ObjectToJson(compact: true);
}
}
/// <summary>
/// JSON-RPC error class. See https://www.jsonrpc.org/specification
/// </summary>
class JsonRpcError
{
public JsonRpcError() { }
public JsonRpcError(int code, string message, object data = null)
{
this.Code = code;
this.Message = message.NonNull();
if (this.Message.IsEmpty()) this.Message = $"JSON-RPC Error {code}";
this.Data = data;
}
[JsonProperty("code")]
public int Code { get; set; } = 0;
[JsonProperty("message")]
public string Message { get; set; } = null;
[JsonProperty("data")]
public object Data { get; set; } = null;
}
/// <summary>
/// JSON-RPC client. See https://www.jsonrpc.org/specification
/// </summary>
class JsonRpcClient
{
HttpClientHandler client_handler;
HttpClient client;
public const int DefaultTimeoutMsecs = 60 * 1000;
public int TimeoutMsecs { get => (int)client.Timeout.TotalMilliseconds; set => client.Timeout = new TimeSpan(0, 0, 0, 0, value); }
public Dictionary<string, string> HttpHeaders { get; } = new Dictionary<string, string>();
string base_url;
/// <summary>
/// JSON-RPC client class constructor
/// </summary>
/// <param name="url">The URL</param>
/// <param name="cert_check_proc">The SSL certificate validation callback</param>
public JsonRpcClient(string url, Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> cert_check_proc = null)
{
if (cert_check_proc == null) cert_check_proc = (message, cert, chain, errors) => true;
client_handler = new HttpClientHandler();
this.client_handler.AllowAutoRedirect = true;
this.client_handler.MaxAutomaticRedirections = 10;
client_handler.ServerCertificateCustomValidationCallback = cert_check_proc;
client = new HttpClient(client_handler, true);
//Console.WriteLine("new HttpClient(client_handler, true);");
this.base_url = url;
this.TimeoutMsecs = DefaultTimeoutMsecs;
}
/// <summary>
/// Call a single RPC call (without error check). You can wait for the response with Task<string> or await statement.
/// </summary>
/// <param name="method_name">The name of RPC method</param>
/// <param name="param">The parameters</param>
public async Task<string> CallInternalAsync(string method_name, object param)
{
string id = DateTime.Now.Ticks.ToString();
JsonRpcRequest req = new JsonRpcRequest(method_name, param, id);
string req_string = req.ObjectToJson();
//Console.WriteLine($"req: {req_string}");
HttpContent content = new StringContent(req_string, Encoding.UTF8, "application/json");
foreach (string key in this.HttpHeaders.Keys)
{
string value = this.HttpHeaders[key];
content.Headers.Add(key, value);
}
HttpResponseMessage response = await this.client.PostAsync(base_url, content);
Stream responseStream = await response.Content.ReadAsStreamAsync();
if (!response.IsSuccessStatusCode)
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
throw new Exception($"Error: {response.StatusCode}: {await streamReader.ReadToEndAsync()}");
}
}
string ret_string;
using (StreamReader streamReader = new StreamReader(responseStream))
{
ret_string = await streamReader.ReadToEndAsync();
}
//Console.WriteLine($"ret: {ret_string}");
return ret_string;
}
/// <summary>
/// Call a single RPC call (with error check). You can wait for the response with Promise<TResult> or await statement. In the case of error, it will be thrown.
/// </summary>
/// <param name="method_name">The name of RPC method</param>
/// <param name="param">The parameters</param>
public async Task<TResult> CallAsync<TResult>(string method_name, object param)
{
string ret_string = await CallInternalAsync(method_name, param);
JsonRpcResponse <TResult> ret = ret_string.JsonToObject<JsonRpcResponse<TResult>>();
ret.ThrowIfError();
return ret.Result;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>VPNServer_JSONRPC_CodeGen</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Remove="Templates\cs_main.txt" />
<None Remove="Templates\cs_proj.txt" />
<None Remove="Templates\cs_sln.txt" />
<None Remove="Templates\doc.txt" />
<None Remove="Templates\md_html.html" />
<None Remove="Templates\ts_rpc.txt" />
<None Remove="Templates\ts_test.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Templates\cs_main.txt" />
<EmbeddedResource Include="Templates\cs_proj.txt" />
<EmbeddedResource Include="Templates\cs_sln.txt" />
<EmbeddedResource Include="Templates\doc.txt" />
<EmbeddedResource Include="Templates\md_html.html" />
<EmbeddedResource Include="Templates\ts_rpc.txt" />
<EmbeddedResource Include="Templates\ts_test.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.15.4" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2041
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vpnserver-jsonrpc-codegen", "vpnserver-jsonrpc-codegen.csproj", "{00B41CF0-7AE9-4542-9970-77B312412535}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{00B41CF0-7AE9-4542-9970-77B312412535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00B41CF0-7AE9-4542-9970-77B312412535}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00B41CF0-7AE9-4542-9970-77B312412535}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00B41CF0-7AE9-4542-9970-77B312412535}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EBB5B5A2-21A9-42A1-B4F4-7ED92CD8BBC1}
EndGlobalSection
EndGlobal