Work in progress...

This commit is contained in:
Adam Ierymenko 2019-11-04 14:24:37 -08:00
parent 14fab11081
commit 47b4efd49b
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
24 changed files with 2144 additions and 108 deletions

111
attic/webview/.clang-format Normal file
View file

@ -0,0 +1,111 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

256
attic/webview/.clang-tidy Normal file
View file

@ -0,0 +1,256 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,*'
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
User: serge
CheckOptions:
- key: bugprone-argument-comment.StrictMode
value: '0'
- key: bugprone-assert-side-effect.AssertMacros
value: assert
- key: bugprone-assert-side-effect.CheckFunctionCalls
value: '0'
- key: bugprone-dangling-handle.HandleClasses
value: 'std::basic_string_view;std::experimental::basic_string_view'
- key: bugprone-string-constructor.LargeLengthThreshold
value: '8388608'
- key: bugprone-string-constructor.WarnOnLargeLength
value: '1'
- key: cert-dcl59-cpp.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: cert-err09-cpp.CheckThrowTemporaries
value: '1'
- key: cert-err61-cpp.CheckThrowTemporaries
value: '1'
- key: cert-oop11-cpp.IncludeStyle
value: llvm
- key: cppcoreguidelines-no-malloc.Allocations
value: '::malloc;::calloc'
- key: cppcoreguidelines-no-malloc.Deallocations
value: '::free'
- key: cppcoreguidelines-no-malloc.Reallocations
value: '::realloc'
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
value: '::free;::realloc;::freopen;::fclose'
- key: cppcoreguidelines-owning-memory.LegacyResourceProducers
value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
value: ''
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
value: '0'
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
value: '0'
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
value: '0'
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: '0'
- key: google-build-namespaces.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-global-names-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.BranchThreshold
value: '4294967295'
- key: google-readability-function-size.LineThreshold
value: '4294967295'
- key: google-readability-function-size.NestingThreshold
value: '4294967295'
- key: google-readability-function-size.ParameterThreshold
value: '4294967295'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: google-runtime-int.SignedTypePrefix
value: int
- key: google-runtime-int.TypeSuffix
value: ''
- key: google-runtime-int.UnsignedTypePrefix
value: uint
- key: google-runtime-references.WhiteListTypes
value: ''
- key: hicpp-braces-around-statements.ShortStatementLines
value: '0'
- key: hicpp-function-size.BranchThreshold
value: '4294967295'
- key: hicpp-function-size.LineThreshold
value: '4294967295'
- key: hicpp-function-size.NestingThreshold
value: '4294967295'
- key: hicpp-function-size.ParameterThreshold
value: '4294967295'
- key: hicpp-function-size.StatementThreshold
value: '800'
- key: hicpp-member-init.IgnoreArrays
value: '0'
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove
value: '1'
- key: hicpp-named-parameter.IgnoreFailedSplit
value: '0'
- key: hicpp-no-malloc.Allocations
value: '::malloc;::calloc'
- key: hicpp-no-malloc.Deallocations
value: '::free'
- key: hicpp-no-malloc.Reallocations
value: '::realloc'
- key: hicpp-special-member-functions.AllowMissingMoveFunctions
value: '0'
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: '0'
- key: hicpp-use-auto.RemoveStars
value: '0'
- key: hicpp-use-emplace.ContainersWithPushBack
value: '::std::vector;::std::list;::std::deque'
- key: hicpp-use-emplace.SmartPointers
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
- key: hicpp-use-emplace.TupleMakeFunctions
value: '::std::make_pair;::std::make_tuple'
- key: hicpp-use-emplace.TupleTypes
value: '::std::pair;::std::tuple'
- key: hicpp-use-equals-default.IgnoreMacros
value: '1'
- key: hicpp-use-noexcept.ReplacementString
value: ''
- key: hicpp-use-noexcept.UseNoexceptFalse
value: '1'
- key: hicpp-use-nullptr.NullMacros
value: ''
- key: llvm-namespace-comment.ShortNamespaceLines
value: '1'
- key: llvm-namespace-comment.SpacesBeforeComments
value: '1'
- key: misc-definitions-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: misc-definitions-in-headers.UseHeaderFileExtension
value: '1'
- key: misc-misplaced-widening-cast.CheckImplicitCasts
value: '0'
- key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant
value: '1'
- key: misc-sizeof-expression.WarnOnSizeOfConstant
value: '1'
- key: misc-sizeof-expression.WarnOnSizeOfThis
value: '1'
- key: misc-suspicious-enum-usage.StrictMode
value: '0'
- key: misc-suspicious-missing-comma.MaxConcatenatedTokens
value: '5'
- key: misc-suspicious-missing-comma.RatioThreshold
value: '0.200000'
- key: misc-suspicious-missing-comma.SizeThreshold
value: '5'
- key: misc-suspicious-string-compare.StringCompareLikeFunctions
value: ''
- key: misc-suspicious-string-compare.WarnOnImplicitComparison
value: '1'
- key: misc-suspicious-string-compare.WarnOnLogicalNotComparison
value: '0'
- key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries
value: '1'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-make-shared.IgnoreMacros
value: '1'
- key: modernize-make-shared.IncludeStyle
value: '0'
- key: modernize-make-shared.MakeSmartPtrFunction
value: 'std::make_shared'
- key: modernize-make-shared.MakeSmartPtrFunctionHeader
value: memory
- key: modernize-make-unique.IgnoreMacros
value: '1'
- key: modernize-make-unique.IncludeStyle
value: '0'
- key: modernize-make-unique.MakeSmartPtrFunction
value: 'std::make_unique'
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
value: memory
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-pass-by-value.ValuesOnly
value: '0'
- key: modernize-raw-string-literal.ReplaceShorterLiterals
value: '0'
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-replace-random-shuffle.IncludeStyle
value: llvm
- key: modernize-use-auto.RemoveStars
value: '0'
- key: modernize-use-default-member-init.IgnoreMacros
value: '1'
- key: modernize-use-default-member-init.UseAssignment
value: '0'
- key: modernize-use-emplace.ContainersWithPushBack
value: '::std::vector;::std::list;::std::deque'
- key: modernize-use-emplace.SmartPointers
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
- key: modernize-use-emplace.TupleMakeFunctions
value: '::std::make_pair;::std::make_tuple'
- key: modernize-use-emplace.TupleTypes
value: '::std::pair;::std::tuple'
- key: modernize-use-equals-default.IgnoreMacros
value: '1'
- key: modernize-use-noexcept.ReplacementString
value: ''
- key: modernize-use-noexcept.UseNoexceptFalse
value: '1'
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
- key: modernize-use-transparent-functors.SafeMode
value: '0'
- key: modernize-use-using.IgnoreMacros
value: '1'
- key: objc-forbidden-subclassing.ForbiddenSuperClassNames
value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView'
- key: objc-property-declaration.Acronyms
value: 'ASCII;PDF;XML;HTML;URL;RTF;HTTP;TIFF;JPG;PNG;GIF;LZW;ROM;RGB;CMYK;MIDI;FTP'
- key: performance-faster-string-find.StringLikeClasses
value: 'std::basic_string'
- key: performance-for-range-copy.WarnOnAllAutoCopies
value: '0'
- key: performance-inefficient-string-concatenation.StrictMode
value: '0'
- key: performance-inefficient-vector-operation.VectorLikeClasses
value: '::std::vector'
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: '1'
- key: performance-move-constructor-init.IncludeStyle
value: llvm
- key: performance-type-promotion-in-math-fn.IncludeStyle
value: llvm
- key: performance-unnecessary-value-param.IncludeStyle
value: llvm
- key: readability-braces-around-statements.ShortStatementLines
value: '0'
- key: readability-function-size.BranchThreshold
value: '4294967295'
- key: readability-function-size.LineThreshold
value: '4294967295'
- key: readability-function-size.NestingThreshold
value: '4294967295'
- key: readability-function-size.ParameterThreshold
value: '4294967295'
- key: readability-function-size.StatementThreshold
value: '800'
- key: readability-identifier-naming.IgnoreFailedSplit
value: '0'
- key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '0'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '0'
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
value: '0'
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
value: '0'
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
value: '3'
...

1
attic/webview/.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.h linguist-language=c

7
attic/webview/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Build atrifacts
/build
/examples/minimal-go/minimal-go
/examples/minimal/minimal
/examples/minimal/minimal.exe
/examples/minimal/build
/examples/timer-cxx/build

19
attic/webview/.travis.yml Normal file
View file

@ -0,0 +1,19 @@
language: go
go:
- 1.x
matrix:
include:
- os: linux
before_install:
- sudo add-apt-repository ppa:webkit-team/ppa -y
- sudo apt-get update
- sudo apt-get install libwebkit2gtk-4.0-dev -y
env: WEBVIEW=gtk
- os: osx
osx_image: xcode8.3
env: WEBVIEW=cocoa
script:
- make example

21
attic/webview/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Serge Zaitsev
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.

28
attic/webview/Makefile Normal file
View file

@ -0,0 +1,28 @@
WEBVIEW_gtk_FLAGS = -DWEBVIEW_GTK -std=c++14 -Wall -Wextra -pedantic $(shell pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0)
WEBVIEW_cocoa_FLAGS = -DWEBVIEW_COCOA -std=c++14 -Wall -Wextra -pedantic -framework WebKit -mmacosx-version-min=10.11 -DOBJC_OLD_DISPATCH_PROTOTYPES
WEBVIEW_mshtml_FLAGS := -DWEBVIEW_MSHTML -std=c++14 -luser32 -lole32 -loleaut32 -lcomctl32 -luuid -static
WEBVIEW_edge_FLAGS := -DWEBVIEW_EDGE
all:
@echo "make WEBVIEW=... test - build and run tests"
@echo "make WEBVIEW=... lint - run clang-tidy checkers"
@echo "make WEBVIEW=... fmt - run clang-format for all sources"
fmt: webview.h
clang-format -i $^
check-env:
ifndef WEBVIEW_$(WEBVIEW)_FLAGS
$(error "Unknown WEBVIEW value, use WEBVIEW=gtk|cocoa|mshtml|edge")
endif
lint: check-env
clang-tidy example.cc -- $(WEBVIEW_$(WEBVIEW)_FLAGS)
example: check-env example.cc webview.h
$(CXX) example.cc $(WEBVIEW_$(WEBVIEW)_FLAGS) -o example
test: check-env
$(CXX) webview_test.cc $(WEBVIEW_$(WEBVIEW)_FLAGS) -o webview_test
./webview_test
rm webview_test

39
attic/webview/example.cc Normal file
View file

@ -0,0 +1,39 @@
// +build ignore
#include "webview.h"
#ifdef _WIN32
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
#else
int main()
#endif
{
webview::webview w(true, nullptr);
w.set_title("Example");
w.set_size(480, 320, true);
w.bind("noop", [](std::string s) -> std::string { printf("%s\n", s.c_str());return s; });
w.bind("add", [](std::string s) -> std::string {
auto a = std::stoi(webview::json_parse(s, "", 0));
auto b = std::stoi(webview::json_parse(s, "", 1));
return std::to_string(a + b);
});
w.navigate(R"(data:text/html,
<!doctype html>
<html>
<body>hello</body>
<script>
window.onload = function() {
noop('hello').then(function(res) {
console.log('noop res', res);
});
add(1, 2).then(function(res) {
console.log('add res', res);
});
};
</script>
</html>
)");
w.run();
return 0;
}

View file

@ -0,0 +1,15 @@
package main
import (
"github.com/zserge/webview"
)
func main() {
w := webview.New(true)
w.Navigate("https://github.com")
w.SetTitle("Hello")
w.Dispatch(func() {
println("Hello dispatch")
})
w.Run()
}

3
attic/webview/go.mod Normal file
View file

@ -0,0 +1,3 @@
module github.com/zserge/webview
go 1.13

1
attic/webview/webview.cc Normal file
View file

@ -0,0 +1 @@
#include "webview.h"

138
attic/webview/webview.go Normal file
View file

@ -0,0 +1,138 @@
package webview
/*
#cgo linux openbsd freebsd CXXFLAGS: -DWEBVIEW_GTK -std=c++14
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
#cgo darwin CXXFLAGS: -DWEBVIEW_COCOA -std=c++14 -DOBJC_OLD_DISPATCH_PROTOTYPES
#cgo darwin LDFLAGS: -framework WebKit
#cgo windows CXXFLAGS: -DWEBVIEW_MSHTML
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
#define WEBVIEW_HEADER
#include "webview.h"
#include <stdlib.h>
#include <stdint.h>
extern void _webviewDispatchGoCallback(void *);
static inline void _webview_dispatch_cb(webview_t w, void *arg) {
_webviewDispatchGoCallback(arg);
}
static inline void CgoWebViewDispatch(webview_t w, uintptr_t arg) {
webview_dispatch(w, _webview_dispatch_cb, (void *)arg);
}
*/
import "C"
import (
"runtime"
"sync"
"unsafe"
)
func init() {
// Ensure that main.main is called from the main thread
runtime.LockOSThread()
}
type WebView interface {
Run()
Terminate()
Dispatch(f func())
Navigate(url string)
SetTitle(title string)
Window() unsafe.Pointer
Init(js string)
Eval(js string)
Destroy()
/*
SetBounds(x, y, width, height int)
Bounds() (x, y, width, height int)
Bind(name string, v interface{})
*/
}
type webview struct {
w C.webview_t
}
var (
m sync.Mutex
index uintptr
dispatch = map[uintptr]func(){}
)
func boolToInt(b bool) C.int {
if b {
return 1
}
return 0
}
func New(debug bool) WebView { return NewWindow(debug, nil) }
func NewWindow(debug bool, window unsafe.Pointer) WebView {
w := &webview{}
q
return w
}
func (w *webview) Destroy() {
C.webview_destroy(w.w)
}
func (w *webview) Run() {
C.webview_run(w.w)
}
func (w *webview) Terminate() {
C.webview_terminate(w.w)
}
func (w *webview) Window() unsafe.Pointer {
return C.webview_get_window(w.w)
}
func (w *webview) Navigate(url string) {
s := C.CString(url)
defer C.free(unsafe.Pointer(s))
C.webview_navigate(w.w, s)
}
func (w *webview) SetTitle(title string) {
s := C.CString(title)
defer C.free(unsafe.Pointer(s))
C.webview_set_title(w.w, s)
}
func (w *webview) Init(js string) {
s := C.CString(js)
defer C.free(unsafe.Pointer(s))
C.webview_init(w.w, s)
}
func (w *webview) Eval(js string) {
s := C.CString(js)
defer C.free(unsafe.Pointer(s))
C.webview_eval(w.w, s)
}
func (w *webview) Dispatch(f func()) {
m.Lock()
for ; dispatch[index] != nil; index++ {
}
dispatch[index] = f
m.Unlock()
C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
}
//export _webviewDispatchGoCallback
func _webviewDispatchGoCallback(index unsafe.Pointer) {
var f func()
m.Lock()
f = dispatch[uintptr(index)]
delete(dispatch, uintptr(index))
m.Unlock()
f()
}

1248
attic/webview/webview.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
// +build ignore
#include "webview.h"
#include <cstring>
#include <cassert>
static void test_terminate() {
webview::webview w(false, nullptr);
w.dispatch([&]() { w.terminate(); });
w.run();
}
static void cb_assert_arg(webview_t w, void *arg) {
assert(w != NULL);
assert(memcmp(arg, "arg", 3) == 0);
}
static void cb_terminate(webview_t w, void *arg) {
assert(arg == NULL);
webview_terminate(w);
}
static void test_c_api() {
webview_t w;
w = webview_create(false, NULL);
webview_set_bounds(w, 100, 100, 480, 320, 0);
webview_set_title(w, "Test");
webview_navigate(w, "https://github.com/zserge/webview");
webview_dispatch(w, cb_assert_arg, (void *)"arg");
webview_dispatch(w, cb_terminate, NULL);
webview_run(w);
webview_destroy(w);
}
int main() {
test_terminate();
test_c_api();
return 0;
}

View file

@ -479,7 +479,16 @@ EmbeddedNetworkController::~EmbeddedNetworkController()
void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
{
char tmp[64];
_signingId = signingId;
// Base the identity hash, which is used to generate network tokens, on
// only the type 0 public and private keys so that type 0 identities can
// upgrade without these tokens changing.
Identity downgraded;
_signingId.downgrade(downgraded,Identity::C25519);
downgraded.hash(_signingIdHash,true);
_sender = sender;
_signingIdAddressString = signingId.address().toString(tmp);
@ -1445,6 +1454,7 @@ void EmbeddedNetworkController::_request(
const bool noAutoAssignIps = OSUtils::jsonBool(member["noAutoAssignIps"],false);
// Set IPv6 static IPs based on NDP emulated schemes if enabled.
if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) {
if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt());
@ -1456,6 +1466,17 @@ void EmbeddedNetworkController::_request(
}
}
// Generate a unique semi-secret token known only to members and former members
// of this network by hashing the hash of our signing identity (including its
// secret part) with the network ID. Deriving the token like this eliminates the
// need to store it somewhere.
uint64_t tokenHashIn[7];
memcpy(tokenHashIn,_signingIdHash,48);
tokenHashIn[6] = Utils::hton(nwid);
uint64_t tokenHash[6];
SHA384(tokenHash,tokenHashIn,sizeof(tokenHashIn));
nc->token = Utils::ntoh(tokenHash[0]);
bool haveManagedIpv4AutoAssignment = false;
bool haveManagedIpv6AutoAssignment = false; // "special" NDP-emulated address types do not count
json ipAssignments = member["ipAssignments"]; // we want to make a copy

View file

@ -132,6 +132,7 @@ private:
std::string _ztPath;
std::string _path;
Identity _signingId;
uint8_t _signingIdHash[48];
std::string _signingIdAddressString;
NetworkController::Sender *_sender;

View file

@ -43,10 +43,10 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
// hiding record values from anything but the controller or someone who has its key.
uint8_t sha512pk[64];
_myId.sha512PrivateKey(sha512pk);
uint8_t sha384pk[48];
_myId.hash(sha384pk,true);
char maskingKey [128];
Utils::hex(sha512pk,32,maskingKey);
Utils::hex(sha384pk,32,maskingKey);
httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort,600);
int64_t timeRangeStart = 0;

View file

@ -18,6 +18,7 @@ set(core_headers
Credential.hpp
Dictionary.hpp
ECC384.hpp
EphemeralKey.hpp
Hashtable.hpp
Identity.hpp
InetAddress.hpp

118
node/EphemeralKey.hpp Normal file
View file

@ -0,0 +1,118 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_EPHEMERALKEY_HPP
#define ZT_EPHEMERALKEY_HPP
#include "Constants.hpp"
#include "C25519.hpp"
#include "ECC384.hpp"
#include "SHA512.hpp"
#include "Buffer.hpp"
#include "Utils.hpp"
namespace ZeroTier {
#define ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)
#define ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE)
/**
* An ephemeral key exchanged to implement forward secrecy
*
* This key includes both C25519 and ECC384 keys and key agreement executes
* ECDH for both and hashes the results together. This should be able to be
* FIPS compliant (if the C25519 portion is just considered a nonce) while
* simultaneously being more secure than either curve alone.
*
* Serialization includes only the public portion since ephemeral private
* keys are never shared or stored anywhere.
*/
class EphemeralKey
{
public:
enum Type
{
NONE = 0,
C25519ECC384 = 1
};
ZT_ALWAYS_INLINE EphemeralKey() : _priv(nullptr),_type(NONE) {}
ZT_ALWAYS_INLINE ~EphemeralKey()
{
if (_priv) {
Utils::burn(_priv,ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE);
delete [] _priv;
}
}
ZT_ALWAYS_INLINE Type type() const { return (Type)_type; }
ZT_ALWAYS_INLINE bool hasPrivate() const { return (_priv != nullptr); }
ZT_ALWAYS_INLINE void generate()
{
if (!_priv)
_priv = new uint8_t[ZT_EPHEMERAL_KEY_TYPE_1_PRIVATE_SIZE];
C25519::generate(_pub,_priv);
ECC384GenerateKey(_pub + ZT_C25519_PUBLIC_KEY_LEN,_priv + ZT_C25519_PRIVATE_KEY_LEN);
_type = C25519ECC384;
}
ZT_ALWAYS_INLINE bool agree(const EphemeralKey &theirs,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const
{
if ((_priv)&&(_type == 1)) {
uint8_t rawkey[128],h[48];
C25519::agree(_priv,theirs._pub,rawkey);
ECC384ECDH(theirs._pub + ZT_C25519_PUBLIC_KEY_LEN,_priv + ZT_C25519_PRIVATE_KEY_LEN,rawkey + ZT_C25519_SHARED_KEY_LEN);
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
}
return false;
}
template<unsigned int C>
ZT_ALWAYS_INLINE void serialize(Buffer<C> &b) const
{
b.append(_type);
if (_type == C25519ECC384)
b.append(_pub,ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE);
}
template<unsigned int C>
ZT_ALWAYS_INLINE unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
delete [] _priv;
_priv = nullptr;
switch(b[p++]) {
case C25519ECC384:
memcpy(_pub,b.field(p,ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE),ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE);
p += ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE;
break;
default:
_type = NONE;
break;
}
return (p - startAt);
}
private:
uint8_t *_priv;
uint8_t _pub[ZT_EPHEMERAL_KEY_TYPE_1_PUBLIC_SIZE];
uint8_t _type;
};
} // namespace ZeroTier
#endif

View file

@ -100,8 +100,13 @@ void Identity::generate(const Type t)
delete [] genmem;
if (t == P384) {
// We sign with both because in pure FIPS environments we might have to say
// that we do not rely on any non-FIPS algorithms, or may even have to disable
// them.
ECC384GenerateKey(_pub.p384,_priv.p384);
C25519::sign(_priv.c25519,_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.p384s);
C25519::sign(_priv.c25519,_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.c25519s);
SHA384(digest,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE);
ECC384ECDSASign(_priv.p384,digest,_pub.p384s);
}
}
@ -116,7 +121,10 @@ bool Identity::locallyValidate() const
case C25519:
break;
case P384:
if (!C25519::verify(_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.p384s,ZT_C25519_SIGNATURE_LEN))
if (!C25519::verify(_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.c25519s,ZT_C25519_SIGNATURE_LEN))
return false;
SHA384(digest,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE);
if (!ECC384ECDSAVerify(_pub.p384,digest,_pub.p384s))
return false;
default:
return false;

View file

@ -93,39 +93,26 @@ public:
*/
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
/**
* Compute the SHA512 hash of our private key (if we have one)
*
* @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
* @return True on success, false if no private key
*/
ZT_ALWAYS_INLINE bool sha512PrivateKey(void *const sha) const
{
if (_hasPrivate) {
switch(_type) {
case C25519:
SHA512(sha,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
return true;
case P384:
SHA512(sha,&_priv,sizeof(_priv));
return true;
}
}
return false;
}
/**
* @param h Buffer to receive SHA384 of public key(s)
* @param includePrivate If true, hash private key(s) too
*/
ZT_ALWAYS_INLINE bool hash(uint8_t h[48]) const
ZT_ALWAYS_INLINE bool hash(uint8_t h[48],const bool includePrivate) const
{
switch(_type) {
case C25519:
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
if ((_hasPrivate)&&(includePrivate))
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return true;
case P384:
SHA384(h,&_pub,sizeof(_pub));
if ((_hasPrivate)&&(includePrivate))
SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv));
else SHA384(h,&_pub,sizeof(_pub));
return true;
}
return false;
}
@ -155,10 +142,8 @@ public:
case P384:
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
// Signature hash includes the C25519/Ed25519 public key after the message.
// This is an added guard against divorcing these two bound keys.
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
SHA384(h,data,len);
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
@ -185,7 +170,7 @@ public:
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
SHA384(h,data,len);
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
}
break;
@ -247,19 +232,20 @@ public:
/**
* Attempt to generate an older type identity from a newer type
*
* If this identity has its private key this is not transferred to
* the downgraded identity.
*
* @param dest Destination to fill with downgraded identity
* @param toType Desired identity type
*/
ZT_ALWAYS_INLINE bool downgrade(Identity &dest,const Type toType)
{
if ((_type == P384)&&(toType == C25519)) {
if (_type == toType) {
return true;
} else if ((_type == P384)&&(toType == C25519)) {
dest._address = _address;
dest._type = C25519;
dest._hasPrivate = false;
dest._hasPrivate = _hasPrivate;
memcpy(dest._pub.c25519,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
if (_hasPrivate)
memcpy(dest._priv.c25519,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
return true;
}
return false;
@ -270,7 +256,6 @@ public:
*
* @param b Destination buffer to append to
* @param includePrivate If true, include private key component (if present) (default: false)
* @throws std::out_of_range Buffer too small
*/
template<unsigned int C>
ZT_ALWAYS_INLINE void serialize(Buffer<C> &b,bool includePrivate = false) const
@ -291,9 +276,7 @@ public:
case P384:
b.append((uint8_t)P384);
b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
b.append(_pub.p384,ZT_ECC384_PUBLIC_KEY_SIZE);
b.append(_pub.p384s,ZT_C25519_SIGNATURE_LEN);
b.append(&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)(ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE));
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
@ -316,8 +299,6 @@ public:
* @param b Buffer containing serialized data
* @param startAt Index within buffer of serialized data (default: 0)
* @return Length of serialized data read from buffer
* @throws std::out_of_range Serialized data invalid
* @throws std::invalid_argument Serialized data invalid
*/
template<unsigned int C>
ZT_ALWAYS_INLINE unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
@ -347,12 +328,8 @@ public:
break;
case P384:
memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_pub.p384,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
p += ZT_ECC384_PUBLIC_KEY_SIZE;
memcpy(_pub.p384s,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_ECC384_SIGNATURE_SIZE;
memcpy(&_pub,b.field(p,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
p += ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE))
@ -442,16 +419,17 @@ public:
private:
Address _address;
Type _type;
Type _type; // _type determines which fields in _priv and _pub are used
bool _hasPrivate;
ZT_PACKED_STRUCT(struct { // don't re-order these
uint8_t c25519[ZT_C25519_PRIVATE_KEY_LEN];
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
}) _priv;
ZT_PACKED_STRUCT(struct { // don't re-order these
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN];
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE];
uint8_t p384s[ZT_C25519_SIGNATURE_LEN]; // signature of both keys with ed25519 to confirm type 0 extension to type 1
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN]; // Curve25519 and Ed25519 public keys
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
uint8_t c25519s[ZT_C25519_SIGNATURE_LEN]; // signature of both keys with ed25519
uint8_t p384s[ZT_ECC384_SIGNATURE_SIZE]; // signature of both keys with p384
}) _pub;
};

View file

@ -44,6 +44,11 @@ namespace ZeroTier {
*/
class Locator
{
enum ObjectType
{
OBJECT_TYPE_ZEROTIER_NODE = 1
};
friend class SharedPtr<Locator>;
public:

View file

@ -80,7 +80,7 @@ public:
ZT_ALWAYS_INLINE uint32_t adi() const { return _adi; }
/**
* @return 32-bit hash ID of this multicast group
* @return 32-bit non-cryptographic hash ID of this multicast group
*/
ZT_ALWAYS_INLINE uint32_t id() const
{

View file

@ -424,6 +424,10 @@ public:
* <[8] timestamp for determining latency>
* <[...] binary serialized identity (see Identity)>
* <[...] physical destination address of packet>
* [... begin encrypted section ...]
* <[2] 16-bit reserved field, always 0>
* <[2] 16-bit length of locator>
* <[...] locator for this node>
*
* HELLO is sent in the clear as it is how peers share their identity
* public keys.
@ -431,6 +435,12 @@ public:
* Destination address is the actual wire address to which the packet
* was sent. See InetAddress::serialize() for format.
*
* Starting at "begin encrypted section" the reset of the packet is
* encrypted with Salsa20/12. This encryption is technically not
* absolutely required for security as nothing in this packet is
* very sensitive, but hiding the locator and other meta-data slightly
* improves privacy.
*
* OK payload:
* <[8] HELLO timestamp field echo>
* <[1] protocol version>
@ -438,6 +448,7 @@ public:
* <[1] software minor version>
* <[2] software revision>
* <[...] physical destination address of packet>
* <[2] 16-bit reserved field, always 0>
*
* With the exception of the timestamp, the other fields pertain to the
* respondent who is sending OK and are not echoes.
@ -567,17 +578,6 @@ public:
*/
VERB_ECHO = 0x08,
/**
* Announce interest in multicast group(s) (DEPRECATED):
* <[8] 64-bit network ID>
* <[6] multicast Ethernet address>
* <[4] multicast additional distinguishing information (ADI)>
* [... additional tuples of network/address/adi ...]
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_LIKE = 0x09,
/**
* Network credentials push:
* [<[...] one or more certificates of membership>]
@ -783,51 +783,11 @@ public:
*/
VERB_REMOTE_TRACE = 0x15,
/**
* A signed locator for this node:
* <[8] 64-bit flags>
* <[2] 16-bit length of locator>
* <[...] serialized locator>
*
* This message is sent in response to OK(HELLO) and can be pushed
* opportunitistically. Its payload is a signed Locator object that
* attests to where and how this Node may be reached. A locator can
* contain static IPs/ports or other ZeroTier nodes that can be used
* to reach this one.
*
* These Locator objects can be stored e.g. by roots in LF to publish
* node reachability. Since they're signed any node can verify that
* the originating node approves of their content.
*/
VERB_SET_LOCATOR = 0x16,
/**
* A list of peers this node will relay traffic to/from:
* <[2] 16-bit number of peers>
* <[16] 128-bit hash of node public key>
* <[2] 16-bit latency to node or 0 if unspecified>
* <[4] 32-bit max bandwidth in megabits or 0 if unspecified>
* [<[...] additional hash,latency,bandwidth tuples>]
*
* This messages can be pushed to indicate that this peer is willing
* to relay traffic to other peers. It contains a list of 128-bit
* hashes (the first 128 bits of a SHA512) of identity public keys
* of currently reachable and willing-to-relay-for nodes.
*
* This can be used to initiate mesh-like behavior in ZeroTier. The
* peers for which this node is willing to relay are reported as
* hashes of their identity public keys. This prevents this message
* from revealing explicit information about linked peers. The
* receiving peer can only "see" a will-relay entry if it knows the
* identity of the peer it is trying to reach.
*/
VERB_WILL_RELAY = 0x17,
/**
* Multipurpose VL2 network multicast:
* <[5] start of range of addresses for propagation>
* <[5] end of range of addresses for propagation>
* <[1] 8-bit propagation depth / hops>
* <[1] 8-bit propagation depth / hops or 0xff to not propagate>
* <[1] 8-bit length of bloom filter in 256-byte/2048-bit chunks>
* <[...] propagation bloom filter>
* [... start of signed portion ...]
@ -875,7 +835,26 @@ public:
* depth, while frames have the added constraint of being propagated only
* to nodes that subscribe to the target multicast group.
*/
VERB_VL2_MULTICAST = 0x18,
VERB_VL2_MULTICAST = 0x16,
/**
* Negotiate a new ephemeral key:
* <[8] first 64 bits of SHA-384 of currently known key for destination>
* <[...] ephemeral key for sender>
*
* If the 64-bit hash of the currently known key sent by the sender does
* not match the key the destination is currently using, the destination
* will send its own REKEY after sending OK to ensure that keys are up to
* date on both sides. This causes either side sending REKEY to trigger
* an automatic two-way handshake. Either side may therefore rekey at
* any time, though a rate limit should be in effect to prevent flooding.
*
* OK payload:
* <[8] first 64 bits of SHA-384 of received ephemeral key>
*/
VERB_REKEY = 0x17
// TODO: legacy multicast message types must be supported
// protocol max: 0x1f
};