Skip to content

Commit

Permalink
migrate code for github
Browse files Browse the repository at this point in the history
  • Loading branch information
Craig Peterson committed Aug 23, 2016
0 parents commit ef0bbf5
Show file tree
Hide file tree
Showing 359 changed files with 157,476 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/tmp
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) 2015 Stack Overflow

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
251 changes: 251 additions & 0 deletions js/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
"use strict";

var conf = {
registrars: [],
dns_service_providers: [],
domains: []
};

var defaultDsps = [];

function initialize(){
conf = {
registrars: [],
dns_service_providers: [],
domains: []
};
defaultDsps = [];
}

function NewRegistrar(name,type,meta) {
if (type) {
type == "MANUAL";
}
var reg = {name: name, type: type, meta: meta};
conf.registrars.push(reg);
return name;
}

function NewDSP(name, type, meta) {
if ((typeof meta === 'object') && ('ip_conversions' in meta)) {
meta.ip_conversions = format_tt(meta.ip_conversions)
}
var dsp = {name: name, type: type, meta: meta};
conf.dns_service_providers.push(dsp);
return name;
}

function newDomain(name,registrar) {
return {name: name, registrar: registrar, meta:{}, records:[], dsps: [], defaultTTL: 0, nameservers:[]};
}

function processDargs(m, domain) {
// for each modifier, if it is a...
// function: call it with domain
// array: process recursively
// object: merge it into metadata
// string: assume it is a dsp
if (_.isFunction(m)) {
m(domain);
} else if (_.isArray(m)) {
for (var j in m) {
processDargs(m[j], domain)
}
} else if (_.isObject(m)) {
_.extend(domain.meta,m);
} else if (_.isString(m)) {
domain.dsps.push(m);
} else {
console.log("WARNING: domain modifier type unsupported: ", typeof m, " Domain: ", domain)
}
}

// D(name,registrar): Create a DNS Domain. Use the parameters as records and mods.
function D(name,registrar) {
var domain = newDomain(name,registrar);
for (var i = 2; i<arguments.length; i++) {
var m = arguments[i];
processDargs(m, domain)
}
var toAdd = _(defaultDsps).difference(domain.dsps);
_(toAdd).each(function(x) { domain.dsps.push(x)});
conf.domains.push(domain)
}

// TTL(v): Set the TTL for a DNS record.
function TTL(v) {
return function(r) {
r.ttl = v;
}
}

// DefaultTTL(v): Set the default TTL for the domain.
function DefaultTTL(v) {
return function(d) {
d.defaultTTL = v;
}
}

// A(name,ip, recordModifiers...)
function A(name, ip) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"A",name,ip,mods)
}
}

// AAAA(name,ip, recordModifiers...)
function AAAA(name, ip) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"AAAA",name,ip,mods)
}
}

// CNAME(name,target, recordModifiers...)
function CNAME(name, target) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"CNAME",name,target,mods)
}
}

// TXT(name,target, recordModifiers...)
function TXT(name, target) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"TXT",name,target,mods)
}
}

// MX(name,priority,target, recordModifiers...)
function MX(name, priority, target) {
var mods = getModifiers(arguments,3)
return function(d) {
mods.push(priority);
addRecord(d, "MX", name, target, mods)
}
}

// NS(name,target, recordModifiers...)
function NS(name, target) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"NS",name,target,mods)
}
}

// NAMESERVER(name,target)
function NAMESERVER(name, target) {
return function(d) {
d.nameservers.push({name: name, target: target})
}
}

function format_tt(transform_table) {
// Turn [[low: 1, high: 2, newBase: 3], [low: 4, high: 5, newIP: 6]]
// into "1 ~ 2 ~ 3 ~; 4 ~ 5 ~ ~ 6"
var lines = []
for (var i=0; i < transform_table.length; i++) {
var ip = transform_table[i];
var newIP = ip.newIP;
if (newIP){
if(_.isArray(newIP)){
newIP = _.map(newIP,function(i){return num2dot(i)}).join(",")
}else{
newIP = num2dot(newIP);
}
}
var row = [
num2dot(ip.low),
num2dot(ip.high),
num2dot(ip.newBase),
newIP
]
lines.push(row.join(" ~ "))
}
return lines.join(" ; ")
}

// IMPORT_TRANSFORM(translation_table, domain)
function IMPORT_TRANSFORM(translation_table, domain) {
return function(d) {
addRecord(d, "IMPORT_TRANSFORM", "@", domain, [
{'transform_table': format_tt(translation_table)}])
}
}

// PURGE()
function PURGE(d) {
d.KeepUnknown = false
}

// NO_PURGE()
function NO_PURGE(d) {
d.KeepUnknown = true
}

function getModifiers(args,start) {
var mods = [];
for (var i = start;i<args.length; i++) {
mods.push(args[i])
}
return mods;
}

function addRecord(d,type,name,target,mods) {
// if target is number, assume ip address. convert it.
if (_.isNumber(target)) {
target = num2dot(target);
}
var rec = {type: type, name: name, target: target, ttl:d.defaultTTL, priority: 0, meta:{}};
// for each modifier, decide based on type:
// - Function: call is with the record as the argument
// - Object: merge it into the metadata
// - Number: IF MX record assume it is priority
if (mods) {
for (var i = 0; i< mods.length; i++) {
var m = mods[i]
if (_.isFunction(m)) {
m(rec);
} else if (_.isObject(m)) {
//convert transforms to strings
if (m.transform && _.isArray(m.transform)){
m.transform = format_tt(m.transform)
}
_.extend(rec.meta,m);
_.extend(rec.meta,m);
} else if (_.isNumber(m) && type == "MX") {
rec.priority = m;
} else {
console.log("WARNING: Modifier type unsupported:", typeof m, "(Skipping!)");
}
}
}
d.records.push(rec);
}

//ip conversion functions from http://stackoverflow.com/a/8105740/121660
// via http://javascript.about.com/library/blipconvert.htm
function IP(dot)
{
var d = dot.split('.');
return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
}

function num2dot(num)
{
if(num === undefined){
return "";
}
if (_.isString(num)){
return num
}
var d = num%256;
for (var i = 3; i > 0; i--)
{
num = Math.floor(num/256);
d = num%256 + '.' + d;
}
return d;
}
46 changes: 46 additions & 0 deletions js/js.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package js

import (
"encoding/json"

"github.com/StackExchange/dnscontrol/models"

"github.com/robertkrimen/otto"
//load underscore js into vm by default
_ "github.com/robertkrimen/otto/underscore"
)

//ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig.
func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
vm := otto.New()

helperJs := GetHelpers(devMode)
// run helper script to prime vm and initialize variables
if _, err := vm.Run(string(helperJs)); err != nil {
return nil, err
}

// run user script
if _, err := vm.Run(script); err != nil {
return nil, err
}

// export conf as string and unmarshal
value, err := vm.Run(`JSON.stringify(conf)`)
if err != nil {
return nil, err
}
str, err := value.ToString()
if err != nil {
return nil, err
}
conf := &models.DNSConfig{}
if err = json.Unmarshal([]byte(str), conf); err != nil {
return nil, err
}
return conf, nil
}

func GetHelpers(devMode bool) string {
return FSMustString(devMode, "/helpers.js")
}
58 changes: 58 additions & 0 deletions js/js_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package js

import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/StackExchange/dnscontrol/models"
)

const testDir = "js/parse_tests"

func TestParsedFiles(t *testing.T) {
os.Chdir("..") // go up a directory so we helpers.js is in a consistent place.
files, err := ioutil.ReadDir(testDir)
if err != nil {
t.Fatal(err)
}
for _, f := range files {
if filepath.Ext(f.Name()) != ".js" {
continue
}
t.Log(f.Name(), "------")
content, err := ioutil.ReadFile(filepath.Join(testDir, f.Name()))
if err != nil {
t.Fatal(err)
}
conf, err := ExecuteJavascript(string(content), true)
if err != nil {
t.Fatal(err)
}
actualJson, err := json.MarshalIndent(conf, "", " ")
if err != nil {
t.Fatal(err)
}
expectedFile := filepath.Join(testDir, f.Name()[:len(f.Name())-3]+".json")
expectedData, err := ioutil.ReadFile(expectedFile)
if err != nil {
t.Fatal(err)
}
conf = &models.DNSConfig{}
err = json.Unmarshal(expectedData, conf)
if err != nil {
t.Fatal(err)
}
expectedJson, err := json.MarshalIndent(conf, "", " ")
if err != nil {
t.Fatal(err)
}
if string(expectedJson) != string(actualJson) {
t.Error("Expected and actual json don't match")
t.Log("Expected:", string(expectedJson))
t.Log("Actual:", string(actualJson))
}
}
}
6 changes: 6 additions & 0 deletions js/parse_tests/001-basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

var REG = NewRegistrar("Third-Party","NONE");
var CF = NewDSP("Cloudflare", "CLOUDFLAREAPI")
D("foo.com",REG,CF,
A("@","1.2.3.4")
);
Loading

0 comments on commit ef0bbf5

Please sign in to comment.