<commit_before>//go:build !windows
// +build !windows

package graphdriver

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"syscall"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
)

type inode struct {
	Dev uint64
	Ino uint64
}

type platformChowner struct {
	mutex  sync.Mutex
	inodes map[inode]bool
}

func newLChowner() *platformChowner {
	return &platformChowner{
		inodes: make(map[inode]bool),
	}
}

func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
	st, ok := info.Sys().(*syscall.Stat_t)
	if !ok {
		return nil
	}

	i := inode{
		Dev: uint64(st.Dev),
		Ino: uint64(st.Ino),
	}
	c.mutex.Lock()
	_, found := c.inodes[i]
	if !found {
		c.inodes[i] = true
	}
	c.mutex.Unlock()

	if found {
		return nil
	}

	// Map an on-disk UID/GID pair from host to container
	// using the first map, then back to the host using the
	// second map.  Skip that first step if they're 0, to
	// compensate for cases where a parent layer should
	// have had a mapped value, but didn't.
	uid, gid := int(st.Uid), int(st.Gid)
	if toContainer != nil {
		pair := idtools.IDPair{
			UID: uid,
			GID: gid,
		}
		mappedUID, mappedGID, err := toContainer.ToContainer(pair)
		if err != nil {
			if (uid != 0) || (gid != 0) {
				return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
			}
			mappedUID, mappedGID = uid, gid
		}
		uid, gid = mappedUID, mappedGID
	}
	if toHost != nil {
		pair := idtools.IDPair{
			UID: uid,
			GID: gid,
		}
		mappedPair, err := toHost.ToHost(pair)
		if err != nil {
			return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
		}
		uid, gid = mappedPair.UID, mappedPair.GID
	}
	if uid != int(st.Uid) || gid != int(st.Gid) {
		cap, err := system.Lgetxattr(path, "security.capability")
		if err != nil && !errors.Is(err, system.EOPNOTSUPP) && !errors.Is(err, system.EOVERFLOW) && err != system.ErrNotSupportedPlatform {
			return fmt.Errorf("%s: %v", os.Args[0], err)
		}

		// Make the change.
		if err := system.Lchown(path, uid, gid); err != nil {
			return fmt.Errorf("%s: %v", os.Args[0], err)
		}
		// Restore the SUID and SGID bits if they were originally set.
		if (info.Mode()&os.ModeSymlink == 0) && info.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
			if err := system.Chmod(path, info.Mode()); err != nil {
				return fmt.Errorf("%s: %v", os.Args[0], err)
			}
		}
		if cap != nil {
			if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
				return fmt.Errorf("%s: %v", os.Args[0], err)
			}
		}

	}
	return nil
}
<commit_msg>chown: use ToHostOverflow when chowning<commit_after>//go:build !windows
// +build !windows

package graphdriver

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"syscall"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
)

type inode struct {
	Dev uint64
	Ino uint64
}

type platformChowner struct {
	mutex  sync.Mutex
	inodes map[inode]bool
}

func newLChowner() *platformChowner {
	return &platformChowner{
		inodes: make(map[inode]bool),
	}
}

func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
	st, ok := info.Sys().(*syscall.Stat_t)
	if !ok {
		return nil
	}

	i := inode{
		Dev: uint64(st.Dev),
		Ino: uint64(st.Ino),
	}
	c.mutex.Lock()
	_, found := c.inodes[i]
	if !found {
		c.inodes[i] = true
	}
	c.mutex.Unlock()

	if found {
		return nil
	}

	// Map an on-disk UID/GID pair from host to container
	// using the first map, then back to the host using the
	// second map.  Skip that first step if they're 0, to
	// compensate for cases where a parent layer should
	// have had a mapped value, but didn't.
	uid, gid := int(st.Uid), int(st.Gid)
	if toContainer != nil {
		pair := idtools.IDPair{
			UID: uid,
			GID: gid,
		}
		mappedUID, mappedGID, err := toContainer.ToContainer(pair)
		if err != nil {
			if (uid != 0) || (gid != 0) {
				return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
			}
			mappedUID, mappedGID = uid, gid
		}
		uid, gid = mappedUID, mappedGID
	}
	if toHost != nil {
		pair := idtools.IDPair{
			UID: uid,
			GID: gid,
		}
		mappedPair, err := toHost.ToHostOverflow(pair)
		if err != nil {
			return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
		}
		uid, gid = mappedPair.UID, mappedPair.GID
	}
	if uid != int(st.Uid) || gid != int(st.Gid) {
		cap, err := system.Lgetxattr(path, "security.capability")
		if err != nil && !errors.Is(err, system.EOPNOTSUPP) && !errors.Is(err, system.EOVERFLOW) && err != system.ErrNotSupportedPlatform {
			return fmt.Errorf("%s: %v", os.Args[0], err)
		}

		// Make the change.
		if err := system.Lchown(path, uid, gid); err != nil {
			return fmt.Errorf("%s: %v", os.Args[0], err)
		}
		// Restore the SUID and SGID bits if they were originally set.
		if (info.Mode()&os.ModeSymlink == 0) && info.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
			if err := system.Chmod(path, info.Mode()); err != nil {
				return fmt.Errorf("%s: %v", os.Args[0], err)
			}
		}
		if cap != nil {
			if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
				return fmt.Errorf("%s: %v", os.Args[0], err)
			}
		}

	}
	return nil
}
<|endoftext|>


<commit_before>// +build darwin,amd64

// Package mac is the driver to be used for apps that run on MacOS.
// It is build on the top of Cocoa and Webkit.
package mac

/*
#include "driver.h"
#include "bridge.h"
*/
import "C"
import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/murlokswarm/app"
	"github.com/murlokswarm/app/internal/bridge"
	"github.com/murlokswarm/app/internal/core"
	"github.com/murlokswarm/app/internal/logs"
	"github.com/pkg/errors"
)

var (
	driver       *Driver
	goappBundle  = os.Getenv("GOAPP_BUNDLE")
	debug        = os.Getenv("GOAPP_DEBUG") == "true"
	goappLogAddr = os.Getenv("GOAPP_LOGS_ADDR")
	goappLogs    *logs.GoappClient
)

func init() {
	if len(goappBundle) != 0 {
		app.Logger = func(format string, a ...interface{}) {}
		return
	}

	if len(goappLogAddr) != 0 {
		app.EnableDebug(debug)
		goappLogs = logs.NewGoappClient(goappLogAddr, logs.WithColoredPrompt)
		app.Logger = goappLogs.Logger()
		return
	}

	logger := logs.ToWriter(os.Stderr)
	app.Logger = logs.WithColoredPrompt(logger)
}

// Driver is the app.Driver implementation for MacOS.
type Driver struct {
	core.Driver

	// The bundle configuration.
	// Only applied when the app is build with goapp mac build -bundle.
	Bundle Bundle

	// Menubar configuration
	MenubarConfig MenuBarConfig

	// The URL of the component to load in the main window.
	// The main window is not created when OnRun or OnReopen are set.
	URL string

	// The URL of the component to load in the dock.
	DockURL string

	// The func called right after app.Run.
	OnRun func()

	// The handler called when the app is focused.
	OnFocus func()

	// The handler called when the app loses focus.
	OnBlur func()

	// The handler called when the app is reopened.
	OnReopen func(hasVisibleWindows bool)

	// The handler called when a file associated with the app is opened.
	OnFilesOpen func(filenames []string)

	// The handler called when the app URI is invoked.
	OnURLOpen func(u *url.URL)

	// The handler called when the quit button is clicked.
	OnQuit func() bool

	// The handler called when the app is about to exit.
	OnExit func()

	factory      *app.Factory
	elems        *core.ElemDB
	devID        string
	macRPC       bridge.PlatformRPC
	goRPC        bridge.GoRPC
	uichan       chan func()
	stopchan     chan error
	menubar      *Menu
	docktile     *DockTile
	droppedFiles []string
}

// Run satisfies the app.Driver interface.
func (d *Driver) Run(f *app.Factory) error {
	if len(goappBundle) != 0 {
		return d.runGoappBundle()
	}

	if driver != nil {
		return errors.New("running already")
	}

	d.factory = f
	d.elems = core.NewElemDB()
	d.devID = generateDevID()
	d.macRPC.Handler = macCall

	d.goRPC.Handle("driver.OnRun", d.onRun)
	d.goRPC.Handle("driver.OnFocus", d.onFocus)
	d.goRPC.Handle("driver.OnBlur", d.onBlur)
	d.goRPC.Handle("driver.OnReopen", d.onReopen)
	d.goRPC.Handle("driver.OnFilesOpen", d.onFilesOpen)
	d.goRPC.Handle("driver.OnURLOpen", d.onURLOpen)
	d.goRPC.Handle("driver.OnFileDrop", d.onFileDrop)
	d.goRPC.Handle("driver.OnQuit", d.onQuit)
	d.goRPC.Handle("driver.OnExit", d.onExit)

	d.goRPC.Handle("windows.OnMove", handleWindow(onWindowMove))
	d.goRPC.Handle("windows.OnResize", handleWindow(onWindowResize))
	d.goRPC.Handle("windows.OnFocus", handleWindow(onWindowFocus))
	d.goRPC.Handle("windows.OnBlur", handleWindow(onWindowBlur))
	d.goRPC.Handle("windows.OnFullScreen", handleWindow(onWindowFullScreen))
	d.goRPC.Handle("windows.OnExitFullScreen", handleWindow(onWindowExitFullScreen))
	d.goRPC.Handle("windows.OnMinimize", handleWindow(onWindowMinimize))
	d.goRPC.Handle("windows.OnDeminimize", handleWindow(onWindowDeminimize))
	d.goRPC.Handle("windows.OnClose", handleWindow(onWindowClose))
	d.goRPC.Handle("windows.OnCallback", handleWindow(onWindowCallback))
	d.goRPC.Handle("windows.OnNavigate", handleWindow(onWindowNavigate))
	d.goRPC.Handle("windows.OnAlert", handleWindow(onWindowAlert))

	d.goRPC.Handle("menus.OnClose", handleMenu(onMenuClose))
	d.goRPC.Handle("menus.OnCallback", handleMenu(onMenuCallback))

	d.goRPC.Handle("filePanels.OnSelect", handleFilePanel(onFilePanelSelect))
	d.goRPC.Handle("saveFilePanels.OnSelect", handleSaveFilePanel(onSaveFilePanelSelect))

	d.goRPC.Handle("notifications.OnReply", handleNotification(onNotificationReply))

	d.uichan = make(chan func(), 256)
	d.stopchan = make(chan error)
	defer close(d.uichan)
	defer close(d.stopchan)

	driver = d

	if goappLogs != nil {
		go goappLogs.WaitForStop(d.Stop)
	}

	go func() {
		d.stopchan <- d.macRPC.Call("driver.Run", nil, nil)
	}()

	for {
		select {
		case err := <-d.stopchan:
			return err

		case fn := <-d.uichan:
			fn()
		}
	}
}

// AppName satisfies the app.Driver interface.
func (d *Driver) AppName() string {
	var out struct {
		AppName string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	if len(out.AppName) != 0 {
		return out.AppName
	}

	wd, err := os.Getwd()
	if err != nil {
		app.Panic(errors.Wrap(err, "app name unreachable"))
	}

	return filepath.Base(wd)
}

// Resources satisfies the app.Driver interface.
func (d *Driver) Resources(path ...string) string {
	var out struct {
		Resources string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	wd, err := os.Getwd()
	if err != nil {
		app.Panic(errors.Wrap(err, "resources unreachable"))
	}

	if filepath.Dir(out.Resources) == wd {
		out.Resources = filepath.Join(wd, "resources")
	}

	r := filepath.Join(path...)
	return filepath.Join(out.Resources, r)
}

// Storage satisfies the app.Driver interface.
func (d *Driver) Storage(path ...string) string {
	s := filepath.Join(path...)
	return filepath.Join(d.support(), "storage", s)
}

// Render satisfies the app.Driver interface.
func (d *Driver) Render(c app.Compo) {
	e := d.ElemByCompo(c)
	if e.Err() == nil {
		e.(app.ElemWithCompo).Render(c)
	}
}

// ElemByCompo satisfies the app.Driver interface.
func (d *Driver) ElemByCompo(c app.Compo) app.Elem {
	return d.elems.GetByCompo(c)
}

// NewWindow satisfies the app.Driver interface.
func (d *Driver) NewWindow(c app.WindowConfig) app.Window {
	return newWindow(c)
}

// NewContextMenu satisfies the app.Driver interface.
func (d *Driver) NewContextMenu(c app.MenuConfig) app.Menu {
	m := newMenu(c, "context menu")
	if m.Err() != nil {
		return m
	}

	err := d.macRPC.Call("driver.SetContextMenu", nil, m.ID())
	m.SetErr(err)
	return m
}

// NewFilePanel satisfies the app.Driver interface.
func (d *Driver) NewFilePanel(c app.FilePanelConfig) app.Elem {
	return newFilePanel(c)
}

// NewSaveFilePanel satisfies the app.Driver interface.
func (d *Driver) NewSaveFilePanel(c app.SaveFilePanelConfig) app.Elem {
	return newSaveFilePanel(c)
}

// NewShare satisfies the app.Driver interface.
func (d *Driver) NewShare(v interface{}) app.Elem {
	return newSharePanel(v)
}

// NewNotification satisfies the app.Driver interface.
func (d *Driver) NewNotification(c app.NotificationConfig) app.Elem {
	return newNotification(c)
}

// MenuBar satisfies the app.Driver interface.
func (d *Driver) MenuBar() app.Menu {
	return d.menubar
}

// NewStatusMenu satisfies the app.Driver interface.
func (d *Driver) NewStatusMenu(c app.StatusMenuConfig) app.StatusMenu {
	return newStatusMenu(c)
}

// DockTile satisfies the app.Driver interface.
func (d *Driver) DockTile() app.DockTile {
	return d.docktile
}

// CallOnUIGoroutine satisfies the app.Driver interface.
func (d *Driver) CallOnUIGoroutine(f func()) {
	d.uichan <- f
}

// Stop satisfies the app.Driver interface.
func (d *Driver) Stop() {
	if err := d.macRPC.Call("driver.Quit", nil, nil); err != nil {
		d.stopchan <- err
	}
}

func (d *Driver) runGoappBundle() error {
	b, err := json.MarshalIndent(d.Bundle, "", "  ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(goappBundle, b, 0777)
}

func (d *Driver) support() string {
	var out struct {
		Support string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	// Set up the support directory in case of the app is not bundled.
	if strings.HasSuffix(out.Support, "{appname}") {
		wd, err := os.Getwd()
		if err != nil {
			app.Panic(errors.Wrap(err, "support unreachable"))
		}

		appname := filepath.Base(wd) + "-" + d.devID
		out.Support = strings.Replace(out.Support, "{appname}", appname, 1)
	}

	return out.Support
}

func (d *Driver) onRun(in map[string]interface{}) interface{} {
	d.menubar = newMenuBar(d.MenubarConfig)
	d.docktile = newDockTile(app.MenuConfig{URL: d.DockURL})

	if d.OnRun == nil {
		d.OnRun = d.newMainWindow
	}

	d.OnRun()
	return nil
}

func (d *Driver) onFocus(in map[string]interface{}) interface{} {
	if d.OnFocus != nil {
		d.OnFocus()
	}
	return nil
}

func (d *Driver) onBlur(in map[string]interface{}) interface{} {
	if d.OnBlur != nil {
		d.OnBlur()
	}
	return nil
}

func (d *Driver) onReopen(in map[string]interface{}) interface{} {
	if d.OnReopen == nil {
		d.OnReopen = func(hasVisibleWindows bool) {
			if !hasVisibleWindows {
				d.newMainWindow()
			}
		}
	}

	d.OnReopen(in["HasVisibleWindows"].(bool))
	return nil
}

func (d *Driver) onFilesOpen(in map[string]interface{}) interface{} {
	if d.OnFilesOpen != nil {
		d.OnFilesOpen(bridge.Strings(in["Filenames"]))
	}
	return nil
}

func (d *Driver) onURLOpen(in map[string]interface{}) interface{} {
	if d.OnURLOpen != nil {
		u, err := url.Parse(in["URL"].(string))
		if err != nil {
			app.Panic(errors.Wrap(err, "onURLOpen"))
		}
		d.OnURLOpen(u)
	}
	return nil
}

func (d *Driver) onFileDrop(in map[string]interface{}) interface{} {
	d.droppedFiles = bridge.Strings(in["Filenames"])
	return nil
}

func (d *Driver) onQuit(in map[string]interface{}) interface{} {
	out := struct {
		Quit bool
	}{
		Quit: true,
	}

	if d.OnQuit != nil {
		out.Quit = d.OnQuit()
	}
	return out
}

func (d *Driver) onExit(in map[string]interface{}) interface{} {
	if d.OnExit != nil {
		d.OnExit()
	}

	if goappLogs != nil {
		goappLogs.Close()
	}

	return nil
}

func (d *Driver) newMainWindow() {
	app.NewWindow(app.WindowConfig{
		Title:           d.AppName(),
		TitlebarHidden:  true,
		MinWidth:        480,
		Width:           1280,
		MinHeight:       480,
		Height:          768,
		BackgroundColor: "#21252b",
		URL:             d.URL,
	})
}

func generateDevID() string {
	h := md5.New()
	wd, _ := os.Getwd()
	io.WriteString(h, wd)
	return fmt.Sprintf("%x", h.Sum(nil))
}
<commit_msg>mac default main window take the default color (#199)<commit_after>// +build darwin,amd64

// Package mac is the driver to be used for apps that run on MacOS.
// It is build on the top of Cocoa and Webkit.
package mac

/*
#include "driver.h"
#include "bridge.h"
*/
import "C"
import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/murlokswarm/app"
	"github.com/murlokswarm/app/internal/bridge"
	"github.com/murlokswarm/app/internal/core"
	"github.com/murlokswarm/app/internal/logs"
	"github.com/pkg/errors"
)

var (
	driver       *Driver
	goappBundle  = os.Getenv("GOAPP_BUNDLE")
	debug        = os.Getenv("GOAPP_DEBUG") == "true"
	goappLogAddr = os.Getenv("GOAPP_LOGS_ADDR")
	goappLogs    *logs.GoappClient
)

func init() {
	if len(goappBundle) != 0 {
		app.Logger = func(format string, a ...interface{}) {}
		return
	}

	if len(goappLogAddr) != 0 {
		app.EnableDebug(debug)
		goappLogs = logs.NewGoappClient(goappLogAddr, logs.WithColoredPrompt)
		app.Logger = goappLogs.Logger()
		return
	}

	logger := logs.ToWriter(os.Stderr)
	app.Logger = logs.WithColoredPrompt(logger)
}

// Driver is the app.Driver implementation for MacOS.
type Driver struct {
	core.Driver

	// The bundle configuration.
	// Only applied when the app is build with goapp mac build -bundle.
	Bundle Bundle

	// Menubar configuration
	MenubarConfig MenuBarConfig

	// The URL of the component to load in the main window.
	// The main window is not created when OnRun or OnReopen are set.
	URL string

	// The URL of the component to load in the dock.
	DockURL string

	// The func called right after app.Run.
	OnRun func()

	// The handler called when the app is focused.
	OnFocus func()

	// The handler called when the app loses focus.
	OnBlur func()

	// The handler called when the app is reopened.
	OnReopen func(hasVisibleWindows bool)

	// The handler called when a file associated with the app is opened.
	OnFilesOpen func(filenames []string)

	// The handler called when the app URI is invoked.
	OnURLOpen func(u *url.URL)

	// The handler called when the quit button is clicked.
	OnQuit func() bool

	// The handler called when the app is about to exit.
	OnExit func()

	factory      *app.Factory
	elems        *core.ElemDB
	devID        string
	macRPC       bridge.PlatformRPC
	goRPC        bridge.GoRPC
	uichan       chan func()
	stopchan     chan error
	menubar      *Menu
	docktile     *DockTile
	droppedFiles []string
}

// Run satisfies the app.Driver interface.
func (d *Driver) Run(f *app.Factory) error {
	if len(goappBundle) != 0 {
		return d.runGoappBundle()
	}

	if driver != nil {
		return errors.New("running already")
	}

	d.factory = f
	d.elems = core.NewElemDB()
	d.devID = generateDevID()
	d.macRPC.Handler = macCall

	d.goRPC.Handle("driver.OnRun", d.onRun)
	d.goRPC.Handle("driver.OnFocus", d.onFocus)
	d.goRPC.Handle("driver.OnBlur", d.onBlur)
	d.goRPC.Handle("driver.OnReopen", d.onReopen)
	d.goRPC.Handle("driver.OnFilesOpen", d.onFilesOpen)
	d.goRPC.Handle("driver.OnURLOpen", d.onURLOpen)
	d.goRPC.Handle("driver.OnFileDrop", d.onFileDrop)
	d.goRPC.Handle("driver.OnQuit", d.onQuit)
	d.goRPC.Handle("driver.OnExit", d.onExit)

	d.goRPC.Handle("windows.OnMove", handleWindow(onWindowMove))
	d.goRPC.Handle("windows.OnResize", handleWindow(onWindowResize))
	d.goRPC.Handle("windows.OnFocus", handleWindow(onWindowFocus))
	d.goRPC.Handle("windows.OnBlur", handleWindow(onWindowBlur))
	d.goRPC.Handle("windows.OnFullScreen", handleWindow(onWindowFullScreen))
	d.goRPC.Handle("windows.OnExitFullScreen", handleWindow(onWindowExitFullScreen))
	d.goRPC.Handle("windows.OnMinimize", handleWindow(onWindowMinimize))
	d.goRPC.Handle("windows.OnDeminimize", handleWindow(onWindowDeminimize))
	d.goRPC.Handle("windows.OnClose", handleWindow(onWindowClose))
	d.goRPC.Handle("windows.OnCallback", handleWindow(onWindowCallback))
	d.goRPC.Handle("windows.OnNavigate", handleWindow(onWindowNavigate))
	d.goRPC.Handle("windows.OnAlert", handleWindow(onWindowAlert))

	d.goRPC.Handle("menus.OnClose", handleMenu(onMenuClose))
	d.goRPC.Handle("menus.OnCallback", handleMenu(onMenuCallback))

	d.goRPC.Handle("filePanels.OnSelect", handleFilePanel(onFilePanelSelect))
	d.goRPC.Handle("saveFilePanels.OnSelect", handleSaveFilePanel(onSaveFilePanelSelect))

	d.goRPC.Handle("notifications.OnReply", handleNotification(onNotificationReply))

	d.uichan = make(chan func(), 256)
	d.stopchan = make(chan error)
	defer close(d.uichan)
	defer close(d.stopchan)

	driver = d

	if goappLogs != nil {
		go goappLogs.WaitForStop(d.Stop)
	}

	go func() {
		d.stopchan <- d.macRPC.Call("driver.Run", nil, nil)
	}()

	for {
		select {
		case err := <-d.stopchan:
			return err

		case fn := <-d.uichan:
			fn()
		}
	}
}

// AppName satisfies the app.Driver interface.
func (d *Driver) AppName() string {
	var out struct {
		AppName string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	if len(out.AppName) != 0 {
		return out.AppName
	}

	wd, err := os.Getwd()
	if err != nil {
		app.Panic(errors.Wrap(err, "app name unreachable"))
	}

	return filepath.Base(wd)
}

// Resources satisfies the app.Driver interface.
func (d *Driver) Resources(path ...string) string {
	var out struct {
		Resources string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	wd, err := os.Getwd()
	if err != nil {
		app.Panic(errors.Wrap(err, "resources unreachable"))
	}

	if filepath.Dir(out.Resources) == wd {
		out.Resources = filepath.Join(wd, "resources")
	}

	r := filepath.Join(path...)
	return filepath.Join(out.Resources, r)
}

// Storage satisfies the app.Driver interface.
func (d *Driver) Storage(path ...string) string {
	s := filepath.Join(path...)
	return filepath.Join(d.support(), "storage", s)
}

// Render satisfies the app.Driver interface.
func (d *Driver) Render(c app.Compo) {
	e := d.ElemByCompo(c)
	if e.Err() == nil {
		e.(app.ElemWithCompo).Render(c)
	}
}

// ElemByCompo satisfies the app.Driver interface.
func (d *Driver) ElemByCompo(c app.Compo) app.Elem {
	return d.elems.GetByCompo(c)
}

// NewWindow satisfies the app.Driver interface.
func (d *Driver) NewWindow(c app.WindowConfig) app.Window {
	return newWindow(c)
}

// NewContextMenu satisfies the app.Driver interface.
func (d *Driver) NewContextMenu(c app.MenuConfig) app.Menu {
	m := newMenu(c, "context menu")
	if m.Err() != nil {
		return m
	}

	err := d.macRPC.Call("driver.SetContextMenu", nil, m.ID())
	m.SetErr(err)
	return m
}

// NewFilePanel satisfies the app.Driver interface.
func (d *Driver) NewFilePanel(c app.FilePanelConfig) app.Elem {
	return newFilePanel(c)
}

// NewSaveFilePanel satisfies the app.Driver interface.
func (d *Driver) NewSaveFilePanel(c app.SaveFilePanelConfig) app.Elem {
	return newSaveFilePanel(c)
}

// NewShare satisfies the app.Driver interface.
func (d *Driver) NewShare(v interface{}) app.Elem {
	return newSharePanel(v)
}

// NewNotification satisfies the app.Driver interface.
func (d *Driver) NewNotification(c app.NotificationConfig) app.Elem {
	return newNotification(c)
}

// MenuBar satisfies the app.Driver interface.
func (d *Driver) MenuBar() app.Menu {
	return d.menubar
}

// NewStatusMenu satisfies the app.Driver interface.
func (d *Driver) NewStatusMenu(c app.StatusMenuConfig) app.StatusMenu {
	return newStatusMenu(c)
}

// DockTile satisfies the app.Driver interface.
func (d *Driver) DockTile() app.DockTile {
	return d.docktile
}

// CallOnUIGoroutine satisfies the app.Driver interface.
func (d *Driver) CallOnUIGoroutine(f func()) {
	d.uichan <- f
}

// Stop satisfies the app.Driver interface.
func (d *Driver) Stop() {
	if err := d.macRPC.Call("driver.Quit", nil, nil); err != nil {
		d.stopchan <- err
	}
}

func (d *Driver) runGoappBundle() error {
	b, err := json.MarshalIndent(d.Bundle, "", "  ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(goappBundle, b, 0777)
}

func (d *Driver) support() string {
	var out struct {
		Support string
	}

	if err := d.macRPC.Call("driver.Bundle", &out, nil); err != nil {
		app.Panic(err)
	}

	// Set up the support directory in case of the app is not bundled.
	if strings.HasSuffix(out.Support, "{appname}") {
		wd, err := os.Getwd()
		if err != nil {
			app.Panic(errors.Wrap(err, "support unreachable"))
		}

		appname := filepath.Base(wd) + "-" + d.devID
		out.Support = strings.Replace(out.Support, "{appname}", appname, 1)
	}

	return out.Support
}

func (d *Driver) onRun(in map[string]interface{}) interface{} {
	d.menubar = newMenuBar(d.MenubarConfig)
	d.docktile = newDockTile(app.MenuConfig{URL: d.DockURL})

	if d.OnRun == nil {
		d.OnRun = d.newMainWindow
	}

	d.OnRun()
	return nil
}

func (d *Driver) onFocus(in map[string]interface{}) interface{} {
	if d.OnFocus != nil {
		d.OnFocus()
	}
	return nil
}

func (d *Driver) onBlur(in map[string]interface{}) interface{} {
	if d.OnBlur != nil {
		d.OnBlur()
	}
	return nil
}

func (d *Driver) onReopen(in map[string]interface{}) interface{} {
	if d.OnReopen == nil {
		d.OnReopen = func(hasVisibleWindows bool) {
			if !hasVisibleWindows {
				d.newMainWindow()
			}
		}
	}

	d.OnReopen(in["HasVisibleWindows"].(bool))
	return nil
}

func (d *Driver) onFilesOpen(in map[string]interface{}) interface{} {
	if d.OnFilesOpen != nil {
		d.OnFilesOpen(bridge.Strings(in["Filenames"]))
	}
	return nil
}

func (d *Driver) onURLOpen(in map[string]interface{}) interface{} {
	if d.OnURLOpen != nil {
		u, err := url.Parse(in["URL"].(string))
		if err != nil {
			app.Panic(errors.Wrap(err, "onURLOpen"))
		}
		d.OnURLOpen(u)
	}
	return nil
}

func (d *Driver) onFileDrop(in map[string]interface{}) interface{} {
	d.droppedFiles = bridge.Strings(in["Filenames"])
	return nil
}

func (d *Driver) onQuit(in map[string]interface{}) interface{} {
	out := struct {
		Quit bool
	}{
		Quit: true,
	}

	if d.OnQuit != nil {
		out.Quit = d.OnQuit()
	}
	return out
}

func (d *Driver) onExit(in map[string]interface{}) interface{} {
	if d.OnExit != nil {
		d.OnExit()
	}

	if goappLogs != nil {
		goappLogs.Close()
	}

	return nil
}

func (d *Driver) newMainWindow() {
	app.NewWindow(app.WindowConfig{
		Title:          d.AppName(),
		TitlebarHidden: true,
		MinWidth:       480,
		Width:          1280,
		MinHeight:      480,
		Height:         768,
		URL:            d.URL,
	})
}

func generateDevID() string {
	h := md5.New()
	wd, _ := os.Getwd()
	io.WriteString(h, wd)
	return fmt.Sprintf("%x", h.Sum(nil))
}
<|endoftext|>


<commit_before>package netsec

import (
	"errors"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

func guano(pid int) (string, string, error) {
	binDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return "", "", err
	}
	out, err := executeCommand(path.Join(binDir, "guano"), fmt.Sprintf("%d", pid), "eth0")
	if err != nil {
		return "", "", err
	}
	parts := strings.Split(out, " ")
	if len(parts) != 2 {
		return "", "", errors.New("guano is batshit insane.")
	}
	return parts[0], parts[1], nil
}

type ContainerSecurity struct {
	veth           string
	mark           string
	ID             string
	Pid            int
	SecurityGroups map[string][]uint16 // ipgroup name -> ports
}

func (c ContainerSecurity) String() string {
	return fmt.Sprintf("veth %s mark %s id %s pid %d groups %v", c.veth, c.mark, c.ID, c.Pid, c.SecurityGroups)
}

func NewContainerSecurity(id string, pid int, sgs map[string][]uint16) (contSec *ContainerSecurity, err error) {
	contSec = &ContainerSecurity{
		ID:             id,
		Pid:            pid,
		SecurityGroups: sgs,
	}
	for i := 0; i < 5 && err != nil; i++ {
		contSec.mark, contSec.veth, err = guano(pid)
		time.Sleep(1 * time.Second)
	}
	return contSec, err
}

func (c *ContainerSecurity) filterPort(action, ip string, port uint16) error {
	_, err := executeCommand("iptables", action, "FORWARD",
		"-d", ip,
		"-p", "tcp", "--dport", fmt.Sprintf("%d", port),
		"-m", "mark", "--mark", c.mark,
		"-j", "ACCEPT")
	return err
}

func (c *ContainerSecurity) allowPort(ip string, port uint16) error {
	return c.filterPort("-I", ip, port)
}

func (c *ContainerSecurity) rejectPort(ip string, port uint16) error {
	return c.filterPort("-D", ip, port)
}

func (c *ContainerSecurity) markVeth(action string) error {
	_, err := executeCommand("iptables", action, "PREROUTING", "-t", "mangle",
		"-m", "physdev", "--physdev-in", c.veth,
		"-j", "MARK", "--set-mark", c.mark)
	return err
}

func (c *ContainerSecurity) addMark() error {
	return c.markVeth("-I")
}

func (c *ContainerSecurity) delMark() error {
	return c.markVeth("-D")
}
<commit_msg>fix guano loop<commit_after>package netsec

import (
	"errors"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

func guano(pid int) (string, string, error) {
	binDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return "", "", err
	}
	out, err := executeCommand(path.Join(binDir, "guano"), fmt.Sprintf("%d", pid), "eth0")
	if err != nil {
		return "", "", err
	}
	parts := strings.Split(out, " ")
	if len(parts) != 2 {
		return "", "", errors.New("guano is batshit insane.")
	}
	return parts[0], parts[1], nil
}

type ContainerSecurity struct {
	veth           string
	mark           string
	ID             string
	Pid            int
	SecurityGroups map[string][]uint16 // ipgroup name -> ports
}

func (c ContainerSecurity) String() string {
	return fmt.Sprintf("veth %s mark %s id %s pid %d groups %v", c.veth, c.mark, c.ID, c.Pid, c.SecurityGroups)
}

func NewContainerSecurity(id string, pid int, sgs map[string][]uint16) (contSec *ContainerSecurity, err error) {
	contSec = &ContainerSecurity{
		ID:             id,
		Pid:            pid,
		SecurityGroups: sgs,
	}
	for i := 0; i < 5; i++ {
		contSec.mark, contSec.veth, err = guano(pid)
		if err == nil {
			break
		}
		time.Sleep(1 * time.Second)
	}
	return contSec, err
}

func (c *ContainerSecurity) filterPort(action, ip string, port uint16) error {
	_, err := executeCommand("iptables", action, "FORWARD",
		"-d", ip,
		"-p", "tcp", "--dport", fmt.Sprintf("%d", port),
		"-m", "mark", "--mark", c.mark,
		"-j", "ACCEPT")
	return err
}

func (c *ContainerSecurity) allowPort(ip string, port uint16) error {
	return c.filterPort("-I", ip, port)
}

func (c *ContainerSecurity) rejectPort(ip string, port uint16) error {
	return c.filterPort("-D", ip, port)
}

func (c *ContainerSecurity) markVeth(action string) error {
	_, err := executeCommand("iptables", action, "PREROUTING", "-t", "mangle",
		"-m", "physdev", "--physdev-in", c.veth,
		"-j", "MARK", "--set-mark", c.mark)
	return err
}

func (c *ContainerSecurity) addMark() error {
	return c.markVeth("-I")
}

func (c *ContainerSecurity) delMark() error {
	return c.markVeth("-D")
}
<|endoftext|>


<commit_before>package validate

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/intelrdt"
	selinux "github.com/opencontainers/selinux/go-selinux"
)

type Validator interface {
	Validate(*configs.Config) error
}

func New() Validator {
	return &ConfigValidator{}
}

type ConfigValidator struct {
}

func (v *ConfigValidator) Validate(config *configs.Config) error {
	if err := v.rootfs(config); err != nil {
		return err
	}
	if err := v.network(config); err != nil {
		return err
	}
	if err := v.hostname(config); err != nil {
		return err
	}
	if err := v.security(config); err != nil {
		return err
	}
	if err := v.usernamespace(config); err != nil {
		return err
	}
	if err := v.cgroupnamespace(config); err != nil {
		return err
	}
	if err := v.sysctl(config); err != nil {
		return err
	}
	if err := v.intelrdt(config); err != nil {
		return err
	}
	if config.RootlessEUID {
		if err := v.rootlessEUID(config); err != nil {
			return err
		}
	}
	return nil
}

// rootfs validates if the rootfs is an absolute path and is not a symlink
// to the container's root filesystem.
func (v *ConfigValidator) rootfs(config *configs.Config) error {
	if _, err := os.Stat(config.Rootfs); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs)
		}
		return err
	}
	cleaned, err := filepath.Abs(config.Rootfs)
	if err != nil {
		return err
	}
	if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil {
		return err
	}
	if filepath.Clean(config.Rootfs) != cleaned {
		return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs)
	}
	return nil
}

func (v *ConfigValidator) network(config *configs.Config) error {
	if !config.Namespaces.Contains(configs.NEWNET) {
		if len(config.Networks) > 0 || len(config.Routes) > 0 {
			return errors.New("unable to apply network settings without a private NET namespace")
		}
	}
	return nil
}

func (v *ConfigValidator) hostname(config *configs.Config) error {
	if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) {
		return errors.New("unable to set hostname without a private UTS namespace")
	}
	return nil
}

func (v *ConfigValidator) security(config *configs.Config) error {
	// restrict sys without mount namespace
	if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) &&
		!config.Namespaces.Contains(configs.NEWNS) {
		return errors.New("unable to restrict sys entries without a private MNT namespace")
	}
	if config.ProcessLabel != "" && !selinux.GetEnabled() {
		return errors.New("selinux label is specified in config, but selinux is disabled or not supported")
	}

	return nil
}

func (v *ConfigValidator) usernamespace(config *configs.Config) error {
	if config.Namespaces.Contains(configs.NEWUSER) {
		if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
			return errors.New("USER namespaces aren't enabled in the kernel")
		}
	} else {
		if config.UidMappings != nil || config.GidMappings != nil {
			return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config")
		}
	}
	return nil
}

func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error {
	if config.Namespaces.Contains(configs.NEWCGROUP) {
		if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) {
			return errors.New("cgroup namespaces aren't enabled in the kernel")
		}
	}
	return nil
}

// sysctl validates that the specified sysctl keys are valid or not.
// /proc/sys isn't completely namespaced and depending on which namespaces
// are specified, a subset of sysctls are permitted.
func (v *ConfigValidator) sysctl(config *configs.Config) error {
	validSysctlMap := map[string]bool{
		"kernel.msgmax":          true,
		"kernel.msgmnb":          true,
		"kernel.msgmni":          true,
		"kernel.sem":             true,
		"kernel.shmall":          true,
		"kernel.shmmax":          true,
		"kernel.shmmni":          true,
		"kernel.shm_rmid_forced": true,
	}

	for s := range config.Sysctl {
		if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") {
			if config.Namespaces.Contains(configs.NEWIPC) {
				continue
			} else {
				return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s)
			}
		}
		if strings.HasPrefix(s, "net.") {
			if config.Namespaces.Contains(configs.NEWNET) {
				if path := config.Namespaces.PathOf(configs.NEWNET); path != "" {
					if err := checkHostNs(s, path); err != nil {
						return err
					}
				}
				continue
			} else {
				return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", s)
			}
		}
		if config.Namespaces.Contains(configs.NEWUTS) {
			switch s {
			case "kernel.domainname":
				// This is namespaced and there's no explicit OCI field for it.
				continue
			case "kernel.hostname":
				// This is namespaced but there's a conflicting (dedicated) OCI field for it.
				return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname")
			}
		}
		return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s)
	}

	return nil
}

func (v *ConfigValidator) intelrdt(config *configs.Config) error {
	if config.IntelRdt != nil {
		if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() {
			return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled")
		}

		if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" {
			return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
		}
		if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" {
			return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
		}

		if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" {
			return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
		}
		if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" {
			return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
		}
	}

	return nil
}

func isSymbolicLink(path string) (bool, error) {
	fi, err := os.Lstat(path)
	if err != nil {
		return false, err
	}

	return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil
}

// checkHostNs checks whether network sysctl is used in host namespace.
func checkHostNs(sysctlConfig string, path string) error {
	var currentProcessNetns = "/proc/self/ns/net"
	// readlink on the current processes network namespace
	destOfCurrentProcess, err := os.Readlink(currentProcessNetns)
	if err != nil {
		return fmt.Errorf("read soft link %q error", currentProcessNetns)
	}

	// First check if the provided path is a symbolic link
	symLink, err := isSymbolicLink(path)
	if err != nil {
		return fmt.Errorf("could not check that %q is a symlink: %v", path, err)
	}

	if !symLink {
		// The provided namespace is not a symbolic link,
		// it is not the host namespace.
		return nil
	}

	// readlink on the path provided in the struct
	destOfContainer, err := os.Readlink(path)
	if err != nil {
		return fmt.Errorf("read soft link %q error", path)
	}
	if destOfContainer == destOfCurrentProcess {
		return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", sysctlConfig)
	}
	return nil
}
<commit_msg>libct/configs/validate: fix host netns check<commit_after>package validate

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/intelrdt"
	selinux "github.com/opencontainers/selinux/go-selinux"
	"golang.org/x/sys/unix"
)

type Validator interface {
	Validate(*configs.Config) error
}

func New() Validator {
	return &ConfigValidator{}
}

type ConfigValidator struct {
}

func (v *ConfigValidator) Validate(config *configs.Config) error {
	if err := v.rootfs(config); err != nil {
		return err
	}
	if err := v.network(config); err != nil {
		return err
	}
	if err := v.hostname(config); err != nil {
		return err
	}
	if err := v.security(config); err != nil {
		return err
	}
	if err := v.usernamespace(config); err != nil {
		return err
	}
	if err := v.cgroupnamespace(config); err != nil {
		return err
	}
	if err := v.sysctl(config); err != nil {
		return err
	}
	if err := v.intelrdt(config); err != nil {
		return err
	}
	if config.RootlessEUID {
		if err := v.rootlessEUID(config); err != nil {
			return err
		}
	}
	return nil
}

// rootfs validates if the rootfs is an absolute path and is not a symlink
// to the container's root filesystem.
func (v *ConfigValidator) rootfs(config *configs.Config) error {
	if _, err := os.Stat(config.Rootfs); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs)
		}
		return err
	}
	cleaned, err := filepath.Abs(config.Rootfs)
	if err != nil {
		return err
	}
	if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil {
		return err
	}
	if filepath.Clean(config.Rootfs) != cleaned {
		return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs)
	}
	return nil
}

func (v *ConfigValidator) network(config *configs.Config) error {
	if !config.Namespaces.Contains(configs.NEWNET) {
		if len(config.Networks) > 0 || len(config.Routes) > 0 {
			return errors.New("unable to apply network settings without a private NET namespace")
		}
	}
	return nil
}

func (v *ConfigValidator) hostname(config *configs.Config) error {
	if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) {
		return errors.New("unable to set hostname without a private UTS namespace")
	}
	return nil
}

func (v *ConfigValidator) security(config *configs.Config) error {
	// restrict sys without mount namespace
	if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) &&
		!config.Namespaces.Contains(configs.NEWNS) {
		return errors.New("unable to restrict sys entries without a private MNT namespace")
	}
	if config.ProcessLabel != "" && !selinux.GetEnabled() {
		return errors.New("selinux label is specified in config, but selinux is disabled or not supported")
	}

	return nil
}

func (v *ConfigValidator) usernamespace(config *configs.Config) error {
	if config.Namespaces.Contains(configs.NEWUSER) {
		if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
			return errors.New("USER namespaces aren't enabled in the kernel")
		}
	} else {
		if config.UidMappings != nil || config.GidMappings != nil {
			return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config")
		}
	}
	return nil
}

func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error {
	if config.Namespaces.Contains(configs.NEWCGROUP) {
		if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) {
			return errors.New("cgroup namespaces aren't enabled in the kernel")
		}
	}
	return nil
}

// sysctl validates that the specified sysctl keys are valid or not.
// /proc/sys isn't completely namespaced and depending on which namespaces
// are specified, a subset of sysctls are permitted.
func (v *ConfigValidator) sysctl(config *configs.Config) error {
	validSysctlMap := map[string]bool{
		"kernel.msgmax":          true,
		"kernel.msgmnb":          true,
		"kernel.msgmni":          true,
		"kernel.sem":             true,
		"kernel.shmall":          true,
		"kernel.shmmax":          true,
		"kernel.shmmni":          true,
		"kernel.shm_rmid_forced": true,
	}

	for s := range config.Sysctl {
		if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") {
			if config.Namespaces.Contains(configs.NEWIPC) {
				continue
			} else {
				return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s)
			}
		}
		if strings.HasPrefix(s, "net.") {
			if config.Namespaces.Contains(configs.NEWNET) {
				if path := config.Namespaces.PathOf(configs.NEWNET); path != "" {
					if err := checkHostNs(s, path); err != nil {
						return err
					}
				}
				continue
			} else {
				return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", s)
			}
		}
		if config.Namespaces.Contains(configs.NEWUTS) {
			switch s {
			case "kernel.domainname":
				// This is namespaced and there's no explicit OCI field for it.
				continue
			case "kernel.hostname":
				// This is namespaced but there's a conflicting (dedicated) OCI field for it.
				return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname")
			}
		}
		return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s)
	}

	return nil
}

func (v *ConfigValidator) intelrdt(config *configs.Config) error {
	if config.IntelRdt != nil {
		if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() {
			return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled")
		}

		if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" {
			return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
		}
		if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" {
			return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
		}

		if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" {
			return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
		}
		if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" {
			return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
		}
	}

	return nil
}

func isHostNetNS(path string) (bool, error) {
	const currentProcessNetns = "/proc/self/ns/net"

	var st1, st2 unix.Stat_t

	if err := unix.Stat(currentProcessNetns, &st1); err != nil {
		return false, fmt.Errorf("unable to stat %q: %s", currentProcessNetns, err)
	}
	if err := unix.Stat(path, &st2); err != nil {
		return false, fmt.Errorf("unable to stat %q: %s", path, err)
	}

	return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil
}

// checkHostNs checks whether network sysctl is used in host namespace.
func checkHostNs(sysctlConfig string, path string) error {
	host, err := isHostNetNS(path)
	if err != nil {
		return err
	}
	if host {
		return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", sysctlConfig)
	}
	return nil
}
<|endoftext|>


<commit_before>package drouter

import (
	"net"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/TrilliumIT/iputil"
	"github.com/vishvananda/netlink"
)

type p2pNetwork struct {
	network       *net.IPNet
	hostIP        net.IP
	selfIP        net.IP
	hostNamespace *netlink.Handle
	hostUnderlay  *net.IPNet
}

func newP2PNetwork(p2paddr string) (*p2pNetwork, error) {
	hns, err := netlinkHandleFromPid(1)
	if err != nil {
		log.Error("Failed to get the host's namespace.")
		return nil, err
	}

	log.Debugf("Making a p2p network for: %v", p2paddr)

	//check if drouter_veth0 already exists
	host_link, err := hns.LinkByName("drouter_veth0")
	if err == nil {
		//exists already... delete
		hns.LinkDel(host_link)
	}
	err = nil

	host_link_veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "drouter_veth0"},
		PeerName:  "drouter_veth1",
	}
	err = hns.LinkAdd(host_link_veth)
	if err != nil {
		return nil, err
	}
	host_link, err = hns.LinkByName("drouter_veth0")
	if err != nil {
		return nil, err
	}

	int_link, err := hns.LinkByName("drouter_veth1")
	if err != nil {
		return nil, err
	}
	err = hns.LinkSetNsPid(int_link, os.Getpid())
	if err != nil {
		return nil, err
	}
	int_link, err = netlink.LinkByName("drouter_veth1")
	if err != nil {
		return nil, err
	}

	_, p2pIPNet, err := net.ParseCIDR(p2paddr)
	if err != nil {
		log.Errorf("Failed to parse the CIDR string for p2p network: %v", p2paddr)
		return nil, err
	}

	host_addr := *p2pIPNet
	host_addr.IP = iputil.IPAdd(host_addr.IP, 1)
	host_netlink_addr := &netlink.Addr{
		IPNet: &host_addr,
		Label: "",
	}
	err = hns.AddrAdd(host_link, host_netlink_addr)
	if err != nil {
		return nil, err
	}

	int_addr := *p2pIPNet
	int_addr.IP = iputil.IPAdd(int_addr.IP, 2)
	int_netlink_addr := &netlink.Addr{
		IPNet: &int_addr,
		Label: "",
	}
	err = netlink.AddrAdd(int_link, int_netlink_addr)
	if err != nil {
		return nil, err
	}

	err = netlink.LinkSetUp(int_link)
	if err != nil {
		return nil, err
	}

	err = hns.LinkSetUp(host_link)
	if err != nil {
		return nil, err
	}

	//discover host underlay address/network
	hunderlay := &net.IPNet{}
	hroutes, err := hns.RouteList(nil, netlink.FAMILY_V4)
	if err != nil {
		return nil, err
	}
Hroutes:
	for _, r := range hroutes {
		if r.Gw != nil {
			continue
		}
		link, err := hns.LinkByIndex(r.LinkIndex)
		if err != nil {
			return nil, err
		}
		addrs, err := hns.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			if !addr.IP.Equal(r.Src) {
				continue
			}
			hunderlay.IP = addr.IP
			hunderlay.Mask = addr.Mask
			break Hroutes
		}
	}

	log.Debugf("Discovered host underlay as: %v", hunderlay)

	staticRoutes = append(staticRoutes, iputil.NetworkID(hunderlay))

	hroute := &netlink.Route{
		LinkIndex: int_link.Attrs().Index,
		Dst:       iputil.NetworkID(hunderlay),
		Gw:        host_addr.IP,
	}

	log.Debug("Adding drouter route to %v via %v.", hroute.Dst, hroute.Gw)
	err = netlink.RouteAdd(hroute)
	if err != nil {
		return nil, err
	}

	p2pnet := &p2pNetwork{
		network:       p2pIPNet,
		hostIP:        host_addr.IP,
		selfIP:        int_addr.IP,
		hostNamespace: hns,
		hostUnderlay:  hunderlay,
	}

	for _, sr := range staticRoutes {
		if iputil.SubnetContainsSubnet(hroute.Dst, sr) {
			log.Debugf("Skipping static route %v covered by host underlay: %v", sr, hroute.Dst)
			continue
		}
		go p2pnet.addHostRoute(sr)
	}

	return p2pnet, nil
}

func (p *p2pNetwork) remove() error {
	host_link, err := p.hostNamespace.LinkByName("drouter_veth0")
	if err != nil {
		return err
	}

	return p.hostNamespace.LinkDel(host_link)
}

func (p *p2pNetwork) addHostRoute(sn *net.IPNet) {
	route := &netlink.Route{
		Gw:  p.selfIP,
		Dst: sn,
		Src: p.hostUnderlay.IP,
	}
	if (route.Dst.IP.To4() == nil) != (route.Gw.To4() == nil) {
		// Dst is a different IP family
		return
	}

	log.Debugf("Injecting shortcut route to %v via drouter into host routing table.", sn)
	err := p.hostNamespace.RouteAdd(route)
	if err != nil {
		log.Error(err)
	}
}

func (p *p2pNetwork) delHostRoute(sn *net.IPNet) {
	route := &netlink.Route{
		Gw:  p.selfIP,
		Dst: sn,
	}
	if (route.Dst.IP.To4() == nil) != (route.Gw.To4() == nil) {
		// Dst is a different IP family
		return
	}

	log.Debugf("Removing shortcut route to %v via drouter from host routing table.", sn)
	err := p.hostNamespace.RouteDel(route)
	if err != nil {
		log.Error(err)
	}
}
<commit_msg>p2p logging<commit_after>package drouter

import (
	"net"
	"os"
	"sync"

	log "github.com/Sirupsen/logrus"
	"github.com/TrilliumIT/iputil"
	"github.com/vishvananda/netlink"
)

type p2pNetwork struct {
	network       *net.IPNet
	hostIP        net.IP
	selfIP        net.IP
	hostNamespace *netlink.Handle
	hostUnderlay  *net.IPNet
	log           *log.Entry
}

func newP2PNetwork(p2paddr string) (*p2pNetwork, error) {
	hns, err := netlinkHandleFromPid(1)
	if err != nil {
		logError("Failed to get the host's namespace.", err)
		return nil, err
	}

	log.WithFields(log.Fields{
		"p2paddr": p2paddr,
	}).Debug("Making p2p network")

	//check if drouter_veth0 already exists
	host_link, err := hns.LinkByName("drouter_veth0")
	if err == nil {
		//exists already... delete
		hns.LinkDel(host_link)
	}
	err = nil

	host_link_veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "drouter_veth0"},
		PeerName:  "drouter_veth1",
	}
	err = hns.LinkAdd(host_link_veth)
	if err != nil {
		logError("Failed to add p2p link", err)
		return nil, err
	}
	host_link, err = hns.LinkByName("drouter_veth0")
	if err != nil {
		log.WithFields(log.Fields{
			"LinkName": "drouter_veth0",
			"Error":    err,
		}).Error("Failed to get p2p link")
		return nil, err
	}

	int_link, err := hns.LinkByName("drouter_veth1")
	if err != nil {
		log.WithFields(log.Fields{
			"LinkName": "drouter_veth1",
			"Error":    err,
		}).Error("Failed to get p2p link")
		return nil, err
	}
	err = hns.LinkSetNsPid(int_link, os.Getpid())
	if err != nil {
		log.WithFields(log.Fields{
			"Pid":   os.Getpid(),
			"Link":  int_link,
			"Error": err,
		}).Error("Failed to put p2p link in self namespace")
		return nil, err
	}
	int_link, err = netlink.LinkByName("drouter_veth1")
	if err != nil {
		log.WithFields(log.Fields{
			"LinkName": "drouter_veth1",
			"Error":    err,
		}).Error("Failed to get p2p link")
		return nil, err
	}

	_, p2pIPNet, err := net.ParseCIDR(p2paddr)
	if err != nil {
		log.WithFields(log.Fields{
			"Subnet": p2paddr,
			"Error":  err,
		}).Error("Failed to Parse p2p subnet.")
		return nil, err
	}

	host_addr := *p2pIPNet
	host_addr.IP = iputil.IPAdd(host_addr.IP, 1)
	host_netlink_addr := &netlink.Addr{
		IPNet: &host_addr,
		Label: "",
	}
	err = hns.AddrAdd(host_link, host_netlink_addr)
	if err != nil {
		log.WithFields(log.Fields{
			"IP":    host_netlink_addr,
			"Link":  host_link,
			"Error": err,
		}).Error("Failed to add IP to link.")
		return nil, err
	}

	int_addr := *p2pIPNet
	int_addr.IP = iputil.IPAdd(int_addr.IP, 2)
	int_netlink_addr := &netlink.Addr{
		IPNet: &int_addr,
		Label: "",
	}
	err = netlink.AddrAdd(int_link, int_netlink_addr)
	if err != nil {
		log.WithFields(log.Fields{
			"IP":    int_netlink_addr,
			"Link":  int_link,
			"Error": err,
		}).Error("Failed to add IP to link.")
	}

	err = netlink.LinkSetUp(int_link)
	if err != nil {
		log.WithFields(log.Fields{
			"Link":  int_link,
			"Error": err,
		}).Error("Failed to set link up.")
		return nil, err
	}

	err = hns.LinkSetUp(host_link)
	if err != nil {
		log.WithFields(log.Fields{
			"Link":  host_link,
			"Error": err,
		}).Error("Failed to set link up.")
		return nil, err
	}

	//discover host underlay address/network
	hunderlay := &net.IPNet{}
	hroutes, err := hns.RouteList(nil, netlink.FAMILY_V4)
	if err != nil {
		logError("Failed to get host routes", err)
		return nil, err
	}
Hroutes:
	for _, r := range hroutes {
		if r.Gw != nil {
			continue
		}
		link, err := hns.LinkByIndex(r.LinkIndex)
		if err != nil {
			log.WithFields(log.Fields{
				"LinkIndex": r.LinkIndex,
				"Error":     err,
			}).Error("Failed to get link.")
			return nil, err
		}
		addrs, err := hns.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			log.WithFields(log.Fields{
				"Link":  link,
				"Error": err,
			}).Error("Failed to get addresses on link.")
			return nil, err
		}
		for _, addr := range addrs {
			if !addr.IP.Equal(r.Src) {
				continue
			}
			hunderlay.IP = addr.IP
			hunderlay.Mask = addr.Mask
			break Hroutes
		}
	}

	log.WithFields(log.Fields{
		"Underlay": hunderlay,
	}).Debug("Discovered host underlay")

	staticRoutes = append(staticRoutes, iputil.NetworkID(hunderlay))

	hroute := &netlink.Route{
		LinkIndex: int_link.Attrs().Index,
		Dst:       iputil.NetworkID(hunderlay),
		Gw:        host_addr.IP,
	}

	log.WithFields(log.Fields{
		"Destination": hunderlay,
		"Gateway":     hroute.Gw,
	}).Debug("Adding underlay route to drouter")
	err = netlink.RouteAdd(hroute)
	if err != nil {
		log.WithFields(log.Fields{
			"Destination": hunderlay,
			"Gateway":     hroute.Gw,
			"Error":       err,
		}).Error("Failed to add underlay route.")
		return nil, err
	}

	p2pnet := &p2pNetwork{
		network:       p2pIPNet,
		hostIP:        host_addr.IP,
		selfIP:        int_addr.IP,
		hostNamespace: hns,
		hostUnderlay:  hunderlay,
		log: log.WithFields(log.Fields{
			"p2p": map[string]interface{}{
				"network": p2pIPNet,
				"hostIP":  host_addr.IP,
				"selfIP":  int_addr.IP,
			}}),
	}

	var hostRouteWG sync.WaitGroup
	for _, sr := range staticRoutes {
		if iputil.SubnetContainsSubnet(hroute.Dst, sr) {
			p2pnet.log.WithFields(log.Fields{
				"Subnet": sr,
			}).Debug("Skipping static route to subnet covered by underlay")
			continue
		}
		p2pnet.log.WithFields(log.Fields{
			"Subnet": sr,
		}).Debug("Asynchronously adding host route to subnet.")
		hostRouteWG.Add(1)
		go func() {
			defer hostRouteWG.Done()
			p2pnet.addHostRoute(sr)
		}()
	}

	p2pnet.log.Debug("Waiting for host route adds to complete.")
	hostRouteWG.Wait()
	return p2pnet, nil
}

func (p *p2pNetwork) remove() error {
	p.log.Debug("Removing p2p network")
	host_link, err := p.hostNamespace.LinkByName("drouter_veth0")
	if err != nil {
		p.log.WithFields(log.Fields{
			"LinkName": "drouter_veth0",
			"Error":    err,
		}).Error("Failed to get p2p link")
		return err
	}

	return p.hostNamespace.LinkDel(host_link)
}

func (p *p2pNetwork) addHostRoute(sn *net.IPNet) {
	p.log.WithFields(log.Fields{
		"Subnet": sn,
	}).Debug("Adding host route to subnet.")
	route := &netlink.Route{
		Gw:  p.selfIP,
		Dst: sn,
		Src: p.hostUnderlay.IP,
	}
	if (route.Dst.IP.To4() == nil) != (route.Gw.To4() == nil) {
		p.log.WithFields(log.Fields{
			"Destination": route.Dst,
			"Gateway":     route.Gw,
		}).Debug("Destination and gateway are different IP family.")
		// Dst is a different IP family
		return
	}

	err := p.hostNamespace.RouteAdd(route)
	if err != nil {
		log.Error(err)
		p.log.WithFields(log.Fields{
			"Destination": route.Dst,
			"Gateway":     route.Gw,
			"Error":       err,
		}).Error("Failed to add host route.")
	}
	p.log.WithFields(log.Fields{
		"Destination": route.Dst,
		"Gateway":     route.Gw,
	}).Error("Successfully added host route.")
}

func (p *p2pNetwork) delHostRoute(sn *net.IPNet) {
	p.log.WithFields(log.Fields{
		"Subnet": sn,
	}).Debug("Deleting host route to subnet.")
	route := &netlink.Route{
		Gw:  p.selfIP,
		Dst: sn,
	}
	if (route.Dst.IP.To4() == nil) != (route.Gw.To4() == nil) {
		// Dst is a different IP family
		p.log.WithFields(log.Fields{
			"Destination": route.Dst,
			"Gateway":     route.Gw,
		}).Debug("Destination and gateway are different IP family.")
		return
	}

	err := p.hostNamespace.RouteDel(route)
	if err != nil {
		p.log.WithFields(log.Fields{
			"Destination": route.Dst,
			"Gateway":     route.Gw,
			"Error":       err,
		}).Error("Failed to delete host route.")
	}
	p.log.WithFields(log.Fields{
		"Destination": route.Dst,
		"Gateway":     route.Gw,
	}).Error("Successfully deleted host route.")
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
	"testing"
)

func TestStrictPolicy(t *testing.T) {

	p := StrictPolicy()

	in := "Hello, World!"
	expected := "Hello, !"
	out := p.Sanitize(in)
	if out != expected {
		t.Errorf(
			"test 1 failed;\ninput   : %s\noutput  : %s\nexpected: %s",
			in,
			out,
			expected,
		)
	}
}

func TestStripTagsPolicy(t *testing.T) {

	type test struct {
		in       string
		expected string
	}

	tests := []test{
		test{in: "Hello, World!", expected: "Hello, World!"},
		test{in: "
Hello, World!", expected: "Hello, World!"},
	}

	p := StripTagsPolicy()

	for ii, test := range tests {
		out := p.Sanitize(test.in)
		if out != test.expected {
			t.Errorf(
				"test %d failed;\ninput   : %s\noutput  : %s\nexpected: %s",
				ii,
				test.in,
				out,
				test.expected,
			)
		}
	}
}

func TestUGCPolicy(t *testing.T) {

	type test struct {
		in       string
		expected string
	}

	tests := []test{
		// Simple formatting
		test{in: "Hello, World!", expected: "Hello, World!"},
		test{in: "Hello, World!", expected: "Hello, World!"},
		// Blocks and formatting
		test{
			in:       "
Hello, World!
",
			expected: "
Hello, World!
",
		},
		test{
			in:       "
Hello, World!
",
			expected: "
Hello, World!
",
		},
		// Inline tags featuring globals
		test{
			in:       `<a href="http://example.org/" rel="nofollow">Hello, <b>World</b></a><a href="https://example.org/#!" rel="nofollow">!</a>`,
			expected: `<a href="http://example.org/" rel="nofollow">Hello, <b>World</b></a><a href="https://example.org/#%21" rel="nofollow">!</a>`,
		},
		test{
			in:       `Hello, <b>World</b><a title="!" href="https://example.org/#!" rel="nofollow">!</a>`,
			expected: `Hello, <b>World</b><a title="!" href="https://example.org/#%21" rel="nofollow">!</a>`,
		},
		// Images
		test{
			in:       `<a href="javascript:alert(1337)">foo</a>`,
			expected: `foo`,
		},
		test{
			in:       `<img src="http://example.org/foo.gif">`,
			expected: `<img src="http://example.org/foo.gif">`,
		},
		test{
			in:       `<img src="http://example.org/x.gif" alt="y" width=96 height=64 border=0>`,
			expected: `<img src="http://example.org/x.gif" alt="y" width="96" height="64">`,
		},
		test{
			in:       `<img src="http://example.org/x.png" alt="y" width="widgy" height=64 border=0>`,
			expected: `<img src="http://example.org/x.png" alt="y" height="64">`,
		},
		// Anchors
		test{
			in:       `<a href="foo.html">Link text</a>`,
			expected: `<a href="foo.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="foo.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="foo.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="http://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="http://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="https://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="https://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="HTTPS://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="https://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="//example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="//example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="javascript:alert(1337).html" onclick="alert(1337)">Link text</a>`,
			expected: `Link text`,
		},
		test{
			in:       `<a name="header" id="header">Header text</a>`,
			expected: `<a id="header">Header text</a>`,
		},
		// Tables
		test{
			in: `<table style="color: rgb(0, 0, 0);">` +
				`<tbody>` +
				`<tr>` +
				`<th>Column One</th><th>Column Two</th>` +
				`</tr>` +
				`<tr>` +
				`<td align="center"` +
				` style="background-color: rgb(255, 255, 254);">` +
				`<font size="2">Size 2</font></td>` +
				`<td align="center"` +
				` style="background-color: rgb(255, 255, 254);">` +
				`<font size="7">Size 7</font></td>` +
				`</tr>` +
				`</tbody>` +
				`</table>`,
			expected: "" +
				`<table>` +
				`<tbody>` +
				`<tr>` +
				`<th>Column One</th><th>Column Two</th>` +
				`</tr>` +
				`<tr>` +
				`<td align="center"></td>` +
				`<td align="center"></td>` +
				`</tr>` +
				`</tbody>` +
				`</table>`,
		},
		// Ordering
		test{
			in:       `xss<a href="http://www.google.de" style="color:red;" onmouseover=alert(1) onmousemove="alert(2)" onclick=alert(3)>g<img src="http://example.org"/>oogle</a>`,
			expected: `xss<a href="http://www.google.de" rel="nofollow">g<img src="http://example.org"/>oogle</a>`,
		},
	}

	p := UGCPolicy()

	for ii, test := range tests {
		out := p.Sanitize(test.in)
		if out != test.expected {
			t.Errorf(
				"test %d failed;\ninput   : %s\noutput  : %s\nexpected: %s",
				ii,
				test.in,
				out,
				test.expected,
			)
		}
	}
}
<commit_msg>Added test for OWASP reported strange behaviour to confirm we are behaving in the expected way<commit_after>// Copyright (c) 2014, David Kitchen <david@buro9.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the organisation (Microcosm) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bluemonday

import (
	"testing"
)

func TestStrictPolicy(t *testing.T) {

	p := StrictPolicy()

	in := "Hello, World!"
	expected := "Hello, !"
	out := p.Sanitize(in)
	if out != expected {
		t.Errorf(
			"test 1 failed;\ninput   : %s\noutput  : %s\nexpected: %s",
			in,
			out,
			expected,
		)
	}
}

func TestStripTagsPolicy(t *testing.T) {

	type test struct {
		in       string
		expected string
	}

	tests := []test{
		test{in: "Hello, World!", expected: "Hello, World!"},
		test{in: "
Hello, World!", expected: "Hello, World!"},
	}

	p := StripTagsPolicy()

	for ii, test := range tests {
		out := p.Sanitize(test.in)
		if out != test.expected {
			t.Errorf(
				"test %d failed;\ninput   : %s\noutput  : %s\nexpected: %s",
				ii,
				test.in,
				out,
				test.expected,
			)
		}
	}
}

func TestUGCPolicy(t *testing.T) {

	type test struct {
		in       string
		expected string
	}

	tests := []test{
		// Simple formatting
		test{in: "Hello, World!", expected: "Hello, World!"},
		test{in: "Hello, World!", expected: "Hello, World!"},
		// Blocks and formatting
		test{
			in:       "
Hello, World!
",
			expected: "
Hello, World!
",
		},
		test{
			in:       "
Hello, World!
",
			expected: "
Hello, World!
",
		},
		// Inline tags featuring globals
		test{
			in:       `<a href="http://example.org/" rel="nofollow">Hello, <b>World</b></a><a href="https://example.org/#!" rel="nofollow">!</a>`,
			expected: `<a href="http://example.org/" rel="nofollow">Hello, <b>World</b></a><a href="https://example.org/#%21" rel="nofollow">!</a>`,
		},
		test{
			in:       `Hello, <b>World</b><a title="!" href="https://example.org/#!" rel="nofollow">!</a>`,
			expected: `Hello, <b>World</b><a title="!" href="https://example.org/#%21" rel="nofollow">!</a>`,
		},
		// Images
		test{
			in:       `<a href="javascript:alert(1337)">foo</a>`,
			expected: `foo`,
		},
		test{
			in:       `<img src="http://example.org/foo.gif">`,
			expected: `<img src="http://example.org/foo.gif">`,
		},
		test{
			in:       `<img src="http://example.org/x.gif" alt="y" width=96 height=64 border=0>`,
			expected: `<img src="http://example.org/x.gif" alt="y" width="96" height="64">`,
		},
		test{
			in:       `<img src="http://example.org/x.png" alt="y" width="widgy" height=64 border=0>`,
			expected: `<img src="http://example.org/x.png" alt="y" height="64">`,
		},
		// Anchors
		test{
			in:       `<a href="foo.html">Link text</a>`,
			expected: `<a href="foo.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="foo.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="foo.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="http://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="http://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="https://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="https://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="HTTPS://example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="https://example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="//example.org/x.html" onclick="alert(1337)">Link text</a>`,
			expected: `<a href="//example.org/x.html" rel="nofollow">Link text</a>`,
		},
		test{
			in:       `<a href="javascript:alert(1337).html" onclick="alert(1337)">Link text</a>`,
			expected: `Link text`,
		},
		test{
			in:       `<a name="header" id="header">Header text</a>`,
			expected: `<a id="header">Header text</a>`,
		},
		// Tables
		test{
			in: `<table style="color: rgb(0, 0, 0);">` +
				`<tbody>` +
				`<tr>` +
				`<th>Column One</th><th>Column Two</th>` +
				`</tr>` +
				`<tr>` +
				`<td align="center"` +
				` style="background-color: rgb(255, 255, 254);">` +
				`<font size="2">Size 2</font></td>` +
				`<td align="center"` +
				` style="background-color: rgb(255, 255, 254);">` +
				`<font size="7">Size 7</font></td>` +
				`</tr>` +
				`</tbody>` +
				`</table>`,
			expected: "" +
				`<table>` +
				`<tbody>` +
				`<tr>` +
				`<th>Column One</th><th>Column Two</th>` +
				`</tr>` +
				`<tr>` +
				`<td align="center"></td>` +
				`<td align="center"></td>` +
				`</tr>` +
				`</tbody>` +
				`</table>`,
		},
		// Ordering
		test{
			in:       `xss<a href="http://www.google.de" style="color:red;" onmouseover=alert(1) onmousemove="alert(2)" onclick=alert(3)>g<img src="http://example.org"/>oogle</a>`,
			expected: `xss<a href="http://www.google.de" rel="nofollow">g<img src="http://example.org"/>oogle</a>`,
		},
		// OWASP 25 June 2014 09:15 Strange behaviour
		test{
			in:       "
Hallo\r\n\nEnde\n\r",
			expected: "
Hallo\n\nEnde",
		},
	}

	p := UGCPolicy()

	for ii, test := range tests {
		out := p.Sanitize(test.in)
		if out != test.expected {
			t.Errorf(
				"test %d failed;\ninput   : %s\noutput  : %s\nexpected: %s",
				ii,
				test.in,
				out,
				test.expected,
			)
		}
	}
}
<|endoftext|>


<commit_before>// Package javascript implements Javascript code generation from compiled VDL packages.
package javascript

// Generates the javascript source code for vdl files.  The generated output in javascript
// differs from most other languages, since we don't generate stubs. Instead generate an
// object that contains the parsed VDL structures that will be used by the Javascript code
// to valid servers.

import (
	"bytes"
	"fmt"
	"strconv"
	"text/template"

	"veyron.io/veyron/veyron2/vdl"
	"veyron.io/veyron/veyron2/vdl/codegen"
	"veyron.io/veyron/veyron2/vdl/compile"
	"veyron.io/veyron/veyron2/vdl/vdlutil"
)

type data struct {
	Pkg            *compile.Package
	Env            *compile.Env
	GenerateImport func(string) string
	UserImports    codegen.Imports
}

// Generate takes a populated compile.Package and produces a byte slice
// containing the generated Javascript code.
func Generate(pkg *compile.Package, env *compile.Env, genImport func(string) string) []byte {
	data := data{
		Pkg:            pkg,
		Env:            env,
		GenerateImport: genImport,
		UserImports:    codegen.ImportsForFiles(pkg.Files...),
	}
	var buf bytes.Buffer
	if err := javascriptTemplate.Execute(&buf, data); err != nil {
		// We shouldn't see an error; it means our template is buggy.
		panic(fmt.Errorf("vdl: couldn't execute template: %v", err))
	}
	return buf.Bytes()
}

var javascriptTemplate *template.Template

func numOutArgs(method *compile.Method) int {
	return len(method.OutArgs) - 1
}

func bitlen(kind vdl.Kind) int {
	switch kind {
	case vdl.Float32, vdl.Complex64:
		return 32
	case vdl.Float64, vdl.Complex128:
		return 64
	}
	panic(fmt.Errorf("vdl: bitLen unhandled kind %v", kind))
}

func genMethodTags(data data, method *compile.Method) string {
	tags := method.Tags
	result := "["
	for _, tag := range tags {
		result += typedConst(data, tag) + ", "
	}
	result += "]"
	return result
}

func unTypedConst(data data, v *vdl.Value) string {
	switch v.Kind() {
	case vdl.Bool:
		if v.Bool() {
			return "true"
		} else {
			return "false"
		}
	case vdl.Byte:
		return strconv.FormatUint(uint64(v.Byte()), 10)
	case vdl.Uint16, vdl.Uint32, vdl.Uint64:
		return strconv.FormatUint(v.Uint(), 10)
	case vdl.Int16, vdl.Int32, vdl.Int64:
		return strconv.FormatInt(v.Int(), 10)
	case vdl.Float32, vdl.Float64:
		return strconv.FormatFloat(v.Float(), 'g', -1, bitlen(v.Kind()))
	case vdl.String:
		return strconv.Quote(v.RawString())
	case vdl.OneOf, vdl.Any, vdl.Nilable:
		if elem := v.Elem(); elem != nil {
			return typedConst(data, elem)
		}
		return "null"
	case vdl.Complex64, vdl.Complex128:
		return fmt.Sprintf("new Complex(%f, %f)", real(v.Complex()), imag(v.Complex()))
	case vdl.Enum:
		return strconv.FormatInt(int64(v.EnumIndex()), 10)
	case vdl.Array, vdl.List:
		s := "["
		for ix := 0; ix < v.Len(); ix++ {
			s += "\n" + typedConst(data, v.Index(ix)) + ","
		}
		return s + "\n]"
	case vdl.Set, vdl.Map:
		s := "{"
		for _, key := range v.Keys() {
			s += "\n  " + unTypedConst(data, key) + ":"
			if v.Kind() == vdl.Set {
				s += "true"
			} else {
				s += typedConst(data, v.MapIndex(key))
			}
			s += ","
			// TODO(bjornick): Deal with non-string keys.
		}
		s += "}"
		return s
	case vdl.Struct:
		s := "{"
		t := v.Type()
		for ix := 0; ix < t.NumField(); ix++ {
			s += "\n  '" + t.Field(ix).Name + "': " + typedConst(data, v.Field(ix)) + ","
		}
		return s + "\n}"

	}

	panic(fmt.Errorf("vdl: unTypedConst unhandled type %v %v", v.Kind(), v.Type()))
}

func typeStruct(t *vdl.Type) string {
	switch t.Kind() {
	case vdl.Any:
		return "Types.ANY"
	case vdl.Bool:
		return "Types.BOOL"
	case vdl.Byte:
		return "Types.BYTE"
	case vdl.Uint16:
		return "Types.UINT16"
	case vdl.Uint32:
		return "Types.UINT32"
	case vdl.Uint64:
		return "Types.UINT64"
	case vdl.Int16:
		return "Types.INT16"
	case vdl.Int32:
		return "Types.INT32"
	case vdl.Int64:
		return "Types.INT64"
	case vdl.Float32:
		return "Types.FLOAT32"
	case vdl.Float64:
		return "Types.FLOAT64"
	case vdl.Complex64:
		return "Types.COMPLEX64"
	case vdl.Complex128:
		return "Types.COMPLEX128"
	case vdl.String:
		return "Types.STRING"
	case vdl.Enum:
		enumRes := `{
    kind: Kind.ENUM,
    name: '` + t.Name() + `',
    labels: [`
		for i := 0; i < t.NumEnumLabel(); i++ {
			enumRes += "'" + t.EnumLabel(i) + "', "
		}
		enumRes += `]
  }`
		return enumRes
	case vdl.TypeVal:
		return "{}"

	// TODO(bjornick): Handle recursive types and de-duping of the same struct definitions over
	// and over again.
	case vdl.Array:
		return fmt.Sprintf(`{
    kind: Kind.ARRAY,
    elem: %s,
    len: %d
  }`, typeStruct(t.Elem()), t.Len())
	case vdl.List:
		return `{
    kind: Kind.LIST,
    elem: ` + typeStruct(t.Elem()) + `
  }`
	case vdl.Set:
		return `{
    kind: Kind.SET,
    key: ` + typeStruct(t.Key()) + `
  }`
	case vdl.Map:
		return fmt.Sprintf(`{
    kind: Kind.MAP,
    key: %s,
    elem: %s
  }`, typeStruct(t.Key()), typeStruct(t.Elem()))
	case vdl.Struct:
		result := `{
    kind: Kind.STRUCT,
    name: '` + t.Name() + `',
    fields: [`
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)
			result += fmt.Sprintf(`
    {
      name: '%s',
      type: %s
    },`, f.Name, typeStruct(f.Type))
		}
		result += "\n  ]}"
		return result
	}
	return ""
}

func qualifiedIdent(data data, name string, file *compile.File) string {
	if data.Pkg.Path == file.Package.Path {
		return name
	}
	return data.UserImports.LookupLocal(file.Package.Path) + "." + name
}

func defaultValue(data data, t *vdl.Type) string {
	if def := data.Env.FindTypeDef(t); def != nil {
		switch {
		case t == vdl.AnyType || t == vdl.TypeValType || t == compile.ErrorType:
			return "null"
		case def.File != compile.BuiltInFile:
			return "new " + qualifiedIdent(data, def.Name, def.File) + "()"
		}
	}
	switch t.Kind() {
	case vdl.Nilable:
		return "null"
	case vdl.Array, vdl.List:
		return "[]"
	case vdl.Set, vdl.Map:
		return "{}"
	case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64:
		return "0"
	case vdl.Complex64, vdl.Complex128:
		return "new Complex(0, 0)"
	case vdl.String:
		return "''"
	case vdl.Bool:
		return "false"
	}
	panic(fmt.Sprintf("Unhandled type %v", t))
}

func generateTypeStub(data data, t *compile.TypeDef) string {
	name := t.Name
	wrappedType := true
	kind := t.Type.Kind()
	// We can't always have Map be a wrapped type, since the key doesn't
	// have to be a string.
	// TODO(bjornick): Handle maps without string keys.
	switch kind {
	case vdl.Struct, vdl.Any, vdl.Enum:
		wrappedType = false
	}

	result := "function " + name + "(val) {"

	if wrappedType {
		result += "\n    this.val = val;\n"
	} else if kind == vdl.Struct {
		result += "\n    val = val || {};"
		for i := 0; i < t.Type.NumField(); i++ {
			field := t.Type.Field(i)
			result += fmt.Sprintf("\n    this.%s = val.%s || %s;", field.Name, field.Name, defaultValue(data, field.Type))
		}
		result += "\n"
	} else if kind == vdl.Enum {
		// The default value of an enum type is the first label which is mapped
		// to 0.
		result += "\n    this.val = 0;\n"
	}
	result += "  }\n"
	result += name + ".prototype._type = " + typeStruct(t.Type) + ";\n"

	result += "  types." + name + " = " + name + ";\n"

	return result
}

func typedConst(data data, v *vdl.Value) string {
	valstr := unTypedConst(data, v)
	t := v.Type()
	if def := data.Env.FindTypeDef(t); def != nil {
		if def.File != compile.BuiltInFile {
			return fmt.Sprintf("new %s(%s)", qualifiedIdent(data, def.Name, def.File), valstr)
		}
	}
	return valstr
}

func generateConstDefinition(data data, c *compile.ConstDef) string {
	return fmt.Sprintf("  %s: %s,", c.Name, typedConst(data, c.Value))
}

func importPath(data data, path string) string {
	return data.GenerateImport(path)

}

func init() {
	funcMap := template.FuncMap{
		"toCamelCase":             vdlutil.ToCamelCase,
		"numOutArgs":              numOutArgs,
		"genMethodTags":           genMethodTags,
		"generateTypeStub":        generateTypeStub,
		"generateConstDefinition": generateConstDefinition,
		"importPath":              importPath,
	}
	javascriptTemplate = template.Must(template.New("genJS").Funcs(funcMap).Parse(genJS))
}

// The template that we execute against a compile.Package instance to generate our
// code.  Most of this is fairly straightforward substitution and ranges; more
// complicated logic is delegated to the helper functions above.
//
// We try to generate code that has somewhat reasonable formatting.
const genJS = `{{with $data := .}}// This file was auto-generated by the veyron vdl tool.
{{$pkg := $data.Pkg}}
{{if $data.UserImports}}{{range $imp := $data.UserImports}}
var {{$imp.Local}} = require('{{importPath $data $imp.Path}}');{{end}}{{end}}
var services = {
package: '{{$pkg.Path}}',
{{range $file := $pkg.Files}}{{range $iface := $file.Interfaces}}  {{$iface.Name}}: {
{{range $method := $iface.AllMethods}}    {{toCamelCase $method.Name}}: {
    numInArgs: {{len $method.InArgs}},
    numOutArgs: {{numOutArgs $method}},
    inputStreaming: {{if $method.InStream}}true{{else}}false{{end}},
    outputStreaming: {{if $method.OutStream}}true{{else}}false{{end}},
    tags: {{genMethodTags $data $method}}
},
{{end}}
},
{{end}}{{end}}
};

var vom = require('vom');
var Types = vom.Types;
var Kind = vom.Kind;
var Complex = vom.Complex;

var types = {};
{{range $file := $pkg.Files}}{{range $type := $file.TypeDefs}}
{{generateTypeStub $data $type}}
{{end}}{{end}}

var consts = { {{range $file := $pkg.Files}}{{range $const := $file.ConstDefs}}
{{generateConstDefinition $data $const}}{{end}}{{end}}
};
module.exports = {
  types: types,
  services: services,
  consts: consts,
};
{{end}}`
<commit_msg>veyron2/vdl: Fix import path logic in javascript.  We need to prefix every path with a "./" so nodejs knows that the paths are relative.<commit_after>// Package javascript implements Javascript code generation from compiled VDL packages.
package javascript

// Generates the javascript source code for vdl files.  The generated output in javascript
// differs from most other languages, since we don't generate stubs. Instead generate an
// object that contains the parsed VDL structures that will be used by the Javascript code
// to valid servers.

import (
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"text/template"

	"veyron.io/veyron/veyron2/vdl"
	"veyron.io/veyron/veyron2/vdl/codegen"
	"veyron.io/veyron/veyron2/vdl/compile"
	"veyron.io/veyron/veyron2/vdl/vdlutil"
)

type data struct {
	Pkg            *compile.Package
	Env            *compile.Env
	GenerateImport func(string) string
	UserImports    codegen.Imports
}

// Generate takes a populated compile.Package and produces a byte slice
// containing the generated Javascript code.
func Generate(pkg *compile.Package, env *compile.Env, genImport func(string) string) []byte {
	data := data{
		Pkg:            pkg,
		Env:            env,
		GenerateImport: genImport,
		UserImports:    codegen.ImportsForFiles(pkg.Files...),
	}
	var buf bytes.Buffer
	if err := javascriptTemplate.Execute(&buf, data); err != nil {
		// We shouldn't see an error; it means our template is buggy.
		panic(fmt.Errorf("vdl: couldn't execute template: %v", err))
	}
	return buf.Bytes()
}

var javascriptTemplate *template.Template

func numOutArgs(method *compile.Method) int {
	return len(method.OutArgs) - 1
}

func bitlen(kind vdl.Kind) int {
	switch kind {
	case vdl.Float32, vdl.Complex64:
		return 32
	case vdl.Float64, vdl.Complex128:
		return 64
	}
	panic(fmt.Errorf("vdl: bitLen unhandled kind %v", kind))
}

func genMethodTags(data data, method *compile.Method) string {
	tags := method.Tags
	result := "["
	for _, tag := range tags {
		result += typedConst(data, tag) + ", "
	}
	result += "]"
	return result
}

func unTypedConst(data data, v *vdl.Value) string {
	switch v.Kind() {
	case vdl.Bool:
		if v.Bool() {
			return "true"
		} else {
			return "false"
		}
	case vdl.Byte:
		return strconv.FormatUint(uint64(v.Byte()), 10)
	case vdl.Uint16, vdl.Uint32, vdl.Uint64:
		return strconv.FormatUint(v.Uint(), 10)
	case vdl.Int16, vdl.Int32, vdl.Int64:
		return strconv.FormatInt(v.Int(), 10)
	case vdl.Float32, vdl.Float64:
		return strconv.FormatFloat(v.Float(), 'g', -1, bitlen(v.Kind()))
	case vdl.String:
		return strconv.Quote(v.RawString())
	case vdl.OneOf, vdl.Any, vdl.Nilable:
		if elem := v.Elem(); elem != nil {
			return typedConst(data, elem)
		}
		return "null"
	case vdl.Complex64, vdl.Complex128:
		return fmt.Sprintf("new Complex(%f, %f)", real(v.Complex()), imag(v.Complex()))
	case vdl.Enum:
		return strconv.FormatInt(int64(v.EnumIndex()), 10)
	case vdl.Array, vdl.List:
		s := "["
		for ix := 0; ix < v.Len(); ix++ {
			s += "\n" + typedConst(data, v.Index(ix)) + ","
		}
		return s + "\n]"
	case vdl.Set, vdl.Map:
		s := "{"
		for _, key := range v.Keys() {
			s += "\n  " + unTypedConst(data, key) + ":"
			if v.Kind() == vdl.Set {
				s += "true"
			} else {
				s += typedConst(data, v.MapIndex(key))
			}
			s += ","
			// TODO(bjornick): Deal with non-string keys.
		}
		s += "}"
		return s
	case vdl.Struct:
		s := "{"
		t := v.Type()
		for ix := 0; ix < t.NumField(); ix++ {
			s += "\n  '" + t.Field(ix).Name + "': " + typedConst(data, v.Field(ix)) + ","
		}
		return s + "\n}"

	}

	panic(fmt.Errorf("vdl: unTypedConst unhandled type %v %v", v.Kind(), v.Type()))
}

func typeStruct(t *vdl.Type) string {
	switch t.Kind() {
	case vdl.Any:
		return "Types.ANY"
	case vdl.Bool:
		return "Types.BOOL"
	case vdl.Byte:
		return "Types.BYTE"
	case vdl.Uint16:
		return "Types.UINT16"
	case vdl.Uint32:
		return "Types.UINT32"
	case vdl.Uint64:
		return "Types.UINT64"
	case vdl.Int16:
		return "Types.INT16"
	case vdl.Int32:
		return "Types.INT32"
	case vdl.Int64:
		return "Types.INT64"
	case vdl.Float32:
		return "Types.FLOAT32"
	case vdl.Float64:
		return "Types.FLOAT64"
	case vdl.Complex64:
		return "Types.COMPLEX64"
	case vdl.Complex128:
		return "Types.COMPLEX128"
	case vdl.String:
		return "Types.STRING"
	case vdl.Enum:
		enumRes := `{
    kind: Kind.ENUM,
    name: '` + t.Name() + `',
    labels: [`
		for i := 0; i < t.NumEnumLabel(); i++ {
			enumRes += "'" + t.EnumLabel(i) + "', "
		}
		enumRes += `]
  }`
		return enumRes
	case vdl.TypeVal:
		return "{}"

	// TODO(bjornick): Handle recursive types and de-duping of the same struct definitions over
	// and over again.
	case vdl.Array:
		return fmt.Sprintf(`{
    kind: Kind.ARRAY,
    elem: %s,
    len: %d
  }`, typeStruct(t.Elem()), t.Len())
	case vdl.List:
		return `{
    kind: Kind.LIST,
    elem: ` + typeStruct(t.Elem()) + `
  }`
	case vdl.Set:
		return `{
    kind: Kind.SET,
    key: ` + typeStruct(t.Key()) + `
  }`
	case vdl.Map:
		return fmt.Sprintf(`{
    kind: Kind.MAP,
    key: %s,
    elem: %s
  }`, typeStruct(t.Key()), typeStruct(t.Elem()))
	case vdl.Struct:
		result := `{
    kind: Kind.STRUCT,
    name: '` + t.Name() + `',
    fields: [`
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)
			result += fmt.Sprintf(`
    {
      name: '%s',
      type: %s
    },`, f.Name, typeStruct(f.Type))
		}
		result += "\n  ]}"
		return result
	}
	return ""
}

func qualifiedIdent(data data, name string, file *compile.File) string {
	if data.Pkg.Path == file.Package.Path {
		return name
	}
	return data.UserImports.LookupLocal(file.Package.Path) + "." + name
}

func defaultValue(data data, t *vdl.Type) string {
	if def := data.Env.FindTypeDef(t); def != nil {
		switch {
		case t == vdl.AnyType || t == vdl.TypeValType || t == compile.ErrorType:
			return "null"
		case def.File != compile.BuiltInFile:
			return "new " + qualifiedIdent(data, def.Name, def.File) + "()"
		}
	}
	switch t.Kind() {
	case vdl.Nilable:
		return "null"
	case vdl.Array, vdl.List:
		return "[]"
	case vdl.Set, vdl.Map:
		return "{}"
	case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64:
		return "0"
	case vdl.Complex64, vdl.Complex128:
		return "new Complex(0, 0)"
	case vdl.String:
		return "''"
	case vdl.Bool:
		return "false"
	}
	panic(fmt.Sprintf("Unhandled type %v", t))
}

func generateTypeStub(data data, t *compile.TypeDef) string {
	name := t.Name
	wrappedType := true
	kind := t.Type.Kind()
	// We can't always have Map be a wrapped type, since the key doesn't
	// have to be a string.
	// TODO(bjornick): Handle maps without string keys.
	switch kind {
	case vdl.Struct, vdl.Any, vdl.Enum:
		wrappedType = false
	}

	result := "function " + name + "(val) {"

	if wrappedType {
		result += "\n    this.val = val;\n"
	} else if kind == vdl.Struct {
		result += "\n    val = val || {};"
		for i := 0; i < t.Type.NumField(); i++ {
			field := t.Type.Field(i)
			result += fmt.Sprintf("\n    this.%s = val.%s || %s;", field.Name, field.Name, defaultValue(data, field.Type))
		}
		result += "\n"
	} else if kind == vdl.Enum {
		// The default value of an enum type is the first label which is mapped
		// to 0.
		result += "\n    this.val = 0;\n"
	}
	result += "  }\n"
	result += name + ".prototype._type = " + typeStruct(t.Type) + ";\n"

	result += "  types." + name + " = " + name + ";\n"

	return result
}

func typedConst(data data, v *vdl.Value) string {
	valstr := unTypedConst(data, v)
	t := v.Type()
	if def := data.Env.FindTypeDef(t); def != nil {
		if def.File != compile.BuiltInFile {
			return fmt.Sprintf("new %s(%s)", qualifiedIdent(data, def.Name, def.File), valstr)
		}
	}
	return valstr
}

func generateConstDefinition(data data, c *compile.ConstDef) string {
	return fmt.Sprintf("  %s: %s,", c.Name, typedConst(data, c.Value))
}

func importPath(data data, path string) string {
	// We need to prefix all of these paths with a ./ to tell node that the path is relative to
	// the current directory.  Sadly filepath.Join(".", foo) == foo, so we have to do it
	// explicitly.
	return "." + string(filepath.Separator) + data.GenerateImport(path)

}

func init() {
	funcMap := template.FuncMap{
		"toCamelCase":             vdlutil.ToCamelCase,
		"numOutArgs":              numOutArgs,
		"genMethodTags":           genMethodTags,
		"generateTypeStub":        generateTypeStub,
		"generateConstDefinition": generateConstDefinition,
		"importPath":              importPath,
	}
	javascriptTemplate = template.Must(template.New("genJS").Funcs(funcMap).Parse(genJS))
}

// The template that we execute against a compile.Package instance to generate our
// code.  Most of this is fairly straightforward substitution and ranges; more
// complicated logic is delegated to the helper functions above.
//
// We try to generate code that has somewhat reasonable formatting.
const genJS = `{{with $data := .}}// This file was auto-generated by the veyron vdl tool.
{{$pkg := $data.Pkg}}
{{if $data.UserImports}}{{range $imp := $data.UserImports}}
var {{$imp.Local}} = require('{{importPath $data $imp.Path}}');{{end}}{{end}}
var services = {
package: '{{$pkg.Path}}',
{{range $file := $pkg.Files}}{{range $iface := $file.Interfaces}}  {{$iface.Name}}: {
{{range $method := $iface.AllMethods}}    {{toCamelCase $method.Name}}: {
    numInArgs: {{len $method.InArgs}},
    numOutArgs: {{numOutArgs $method}},
    inputStreaming: {{if $method.InStream}}true{{else}}false{{end}},
    outputStreaming: {{if $method.OutStream}}true{{else}}false{{end}},
    tags: {{genMethodTags $data $method}}
},
{{end}}
},
{{end}}{{end}}
};

var vom = require('vom');
var Types = vom.Types;
var Kind = vom.Kind;
var Complex = vom.Complex;

var types = {};
{{range $file := $pkg.Files}}{{range $type := $file.TypeDefs}}
{{generateTypeStub $data $type}}
{{end}}{{end}}

var consts = { {{range $file := $pkg.Files}}{{range $const := $file.ConstDefs}}
{{generateConstDefinition $data $const}}{{end}}{{end}}
};
module.exports = {
  types: types,
  services: services,
  consts: consts,
};
{{end}}`
<|endoftext|>


<commit_before>package find

import (
	"net/http"

	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type Handler struct {
	config *config.Config
}

func NewHandler(config *config.Config) *Handler {
	return &Handler{
		config: config,
	}
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(1024 * 1024)

	f, err := New(h.config, r.Context(), r.FormValue("query"))
	if err != nil {
		clickhouse.HandleError(w, err)
		return
	}

	h.Reply(w, r, f)
}

func (h *Handler) Reply(w http.ResponseWriter, r *http.Request, f *Find) {
	switch r.FormValue("format") {
	case "pickle":
		f.WritePickle(w)
	case "protobuf":
		f.WriteProtobuf(w)
	}
}
<commit_msg>check find query param<commit_after>package find

import (
	"net/http"

	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type Handler struct {
	config *config.Config
}

func NewHandler(config *config.Config) *Handler {
	return &Handler{
		config: config,
	}
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(1024 * 1024)

	query := r.FormValue("query")
	if len(query) == 0 {
		http.Error(w, "Query not set", http.StatusBadRequest)
		return
	}
	f, err := New(h.config, r.Context(), query)
	if err != nil {
		clickhouse.HandleError(w, err)
		return
	}

	h.Reply(w, r, f)
}

func (h *Handler) Reply(w http.ResponseWriter, r *http.Request, f *Find) {
	switch r.FormValue("format") {
	case "pickle":
		f.WritePickle(w)
	case "protobuf":
		f.WriteProtobuf(w)
	}
}
<|endoftext|>


<commit_before>package txnmanager

import (
	"database/sql"
	"testing"

	_ "github.com/mattn/go-sqlite3"
)

func setup() (*sql.DB, error) {
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		return nil, err
	}

	_, err = db.Exec(
		"CREATE TABLE t1 (id INTEGER PRIMARY KEY)",
	)
	if err != nil {
		return nil, err
	}

	return db, nil
}

func TestCommit(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	func() {
		tx, err := dbm.TxBegin()
		if err != nil {
			t.Fatalf("beginning transaction failed: %v", err)
		}
		defer tx.TxFinish()

		_, err = tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			t.Fatalf("inserting failed: %v", err)
		}

		if err := tx.TxCommit(); err != nil {
			t.Fatalf("commiting failed: %v", err)
		}
	}()

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}
}

func TestRollback(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	func() {
		tx, err := dbm.TxBegin()
		if err != nil {
			t.Fatalf("beginning transaction failed: %v", err)
		}
		defer tx.TxFinish()

		_, err = tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			t.Fatalf("inserting failed: %v", err)
		}

		if err := tx.TxRollback(); err != nil {
			t.Fatalf("rollback failed: %v", err)
		}
	}()

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != sql.ErrNoRows {
		t.Fatalf("got %v\nwant ErrNoRows", err)
	}
}

func TestDo(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	err = Do(dbm, func(tx Dbm) error {
		_, err := tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		return err
	})
	if err != nil {
		t.Fatalf("do failed: %v", err)
	}

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}
}

func TestNestCommit(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	err = Do(dbm, func(tx1 Dbm) error {
		_, err := tx1.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			return err
		}

		return Do(tx1, func(tx2 Dbm) error {
			_, err := tx2.Exec("INSERT INTO t1 (id) VALUES(2)")
			return err
		})
	})
	if err != nil {
		t.Fatalf("do failed: %v", err)
	}

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}

	row = dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 2)
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 2 {
		t.Errorf("got %d\nwant 2", id)
	}
}
<commit_msg>ネストしたトランザクションをロールバックするテストを追加<commit_after>package txnmanager

import (
	"database/sql"
	"errors"
	"testing"

	_ "github.com/mattn/go-sqlite3"
)

func setup() (*sql.DB, error) {
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		return nil, err
	}

	_, err = db.Exec(
		"CREATE TABLE t1 (id INTEGER PRIMARY KEY)",
	)
	if err != nil {
		return nil, err
	}

	return db, nil
}

func TestCommit(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	func() {
		tx, err := dbm.TxBegin()
		if err != nil {
			t.Fatalf("beginning transaction failed: %v", err)
		}
		defer tx.TxFinish()

		_, err = tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			t.Fatalf("inserting failed: %v", err)
		}

		if err := tx.TxCommit(); err != nil {
			t.Fatalf("commiting failed: %v", err)
		}
	}()

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}
}

func TestRollback(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	func() {
		tx, err := dbm.TxBegin()
		if err != nil {
			t.Fatalf("beginning transaction failed: %v", err)
		}
		defer tx.TxFinish()

		_, err = tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			t.Fatalf("inserting failed: %v", err)
		}

		if err := tx.TxRollback(); err != nil {
			t.Fatalf("rollback failed: %v", err)
		}
	}()

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != sql.ErrNoRows {
		t.Fatalf("got %v\nwant ErrNoRows", err)
	}
}

func TestDo(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	err = Do(dbm, func(tx Dbm) error {
		_, err := tx.Exec("INSERT INTO t1 (id) VALUES(1)")
		return err
	})
	if err != nil {
		t.Fatalf("do failed: %v", err)
	}

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}
}

func TestNestCommit(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	err = Do(dbm, func(tx1 Dbm) error {
		_, err := tx1.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			return err
		}

		return Do(tx1, func(tx2 Dbm) error {
			_, err := tx2.Exec("INSERT INTO t1 (id) VALUES(2)")
			return err
		})
	})
	if err != nil {
		t.Fatalf("do failed: %v", err)
	}

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 1 {
		t.Errorf("got %d\nwant 1", id)
	}

	row = dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 2)
	if err = row.Scan(&id); err != nil {
		t.Fatalf("selecting row failed: %v", err)
	}
	if id != 2 {
		t.Errorf("got %d\nwant 2", id)
	}
}

func TestNestRollback(t *testing.T) {
	db, err := setup()
	if err != nil {
		t.Fatalf("opening database failed: %v", err)
	}
	defer db.Close()

	dbm := NewDbm(db)
	err = Do(dbm, func(tx1 Dbm) error {
		_, err := tx1.Exec("INSERT INTO t1 (id) VALUES(1)")
		if err != nil {
			t.Fatalf("intert failed: %v", err)
		}

		err = Do(tx1, func(tx2 Dbm) error {
			_, err := tx2.Exec("INSERT INTO t1 (id) VALUES(2)")
			return err
		})
		if err != nil {
			t.Fatalf("insert failed: %v", err)
		}

		return errors.New("something wrong. rollback all change.")
	})
	if err == nil {
		t.Fatalf("got no error\nwant fail")
	}

	row := dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 1)
	var id int
	if err = row.Scan(&id); err != sql.ErrNoRows {
		t.Errorf("got %v\nwant ErrNoRows", err)
	}

	row = dbm.QueryRow("SELECT id FROM t1 WHERE id = ?", 2)
	if err = row.Scan(&id); err != sql.ErrNoRows {
		t.Errorf("got %v\nwant ErrNoRows", err)
	}
}
<|endoftext|>