├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── Procfile
├── README.md
├── config
├── config.json-dist
├── defs.js
└── upstart_bip.conf
├── migrations
├── 0.2.44
│ └── index.js
├── 0.2.50
│ └── index.js
├── 0.2.79
│ └── index.js
├── 0.3.0
│ └── index.js
├── 0.3.20
│ └── index.js
├── 0.3.24
│ └── index.js
├── 0.3.39
│ └── index.js
├── 0.3.40
│ └── index.js
├── 0.3.44
│ └── index.js
├── 0.4.16
│ └── index.js
├── 0.4.19
│ └── index.js
└── 0.4.4
│ └── index.js
├── package.json
├── src
├── bootstrap.js
├── lib
│ ├── bastion.js
│ ├── dao-mongo.js
│ ├── dao.js
│ ├── helper.js
│ ├── rabbit.js
│ └── step.js
├── models
│ ├── account.js
│ ├── account_activity.js
│ ├── account_auth.js
│ ├── account_log.js
│ ├── account_option.js
│ ├── bip.js
│ ├── bip_log.js
│ ├── bip_share.js
│ ├── channel.js
│ ├── channel_log.js
│ ├── domain.js
│ ├── migration.js
│ ├── prototype.js
│ ├── stats_account.js
│ ├── stats_account_network.js
│ ├── stats_global.js
│ └── transform_default.js
├── modules
│ ├── auth
│ │ ├── http_basic.js
│ │ ├── ldap.js
│ │ ├── models
│ │ │ └── account_info.js
│ │ └── native.js
│ └── cdn
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── cdn.js
│ │ ├── config.json
│ │ ├── fs.js
│ │ ├── index.js
│ │ ├── package.json
│ │ └── utils.js
├── router.js
├── server.js
└── worker.js
├── tests
├── lib
│ └── helper.js
├── managers
│ ├── dao-mongo.js
│ └── dao.js
├── migrations
│ └── 0.3.0.js
└── models
│ ├── bip.js
│ ├── channel.js
│ └── domain.js
└── tools
├── archive_logs.js
├── avsnarf.js
├── bip-expire.js
├── bip-trigger.js
├── cdnfactory.js
├── create_user.js
├── crypt_get.js
├── gencert.sh
├── generate-hub-stats.js
├── git-setup.sh
├── heapdump.js
├── init-boilerplate.sh
├── login_set.js
├── oauth_refresh.js
├── pause_bip.js
├── pod-install.js
├── post-merge
├── rm_user.js
├── set_user_level.js
├── setup.js
├── test_jwt_token.js
├── token_get.js
├── token_regen.js
├── token_set.js
├── triage.js
└── update-transforms.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /nbproject/private/
2 | node_modules
3 | config/default.json
4 | config/staging.json
5 | config/production.json
6 | config/haraka
7 | config/credentials
8 | data
9 | config/runtime.json
10 | npm-debug.log
11 | sftp_config.json
12 | .DS_Store
13 | src/modules/stats
14 | src/modules/permissions
15 | src/modules/provisioning
16 | src/modules/mozu
17 | logs
18 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /nbproject/private/
2 | node_modules
3 | config/default.json
4 | config/staging.json
5 | config/production.json
6 | config/haraka
7 | data
8 | config/runtime.json
9 | npm-debug.log
10 | src/modules/stats
11 | src/modules/mozu
12 | src/modules/permissions
13 | src/modules/provisioning
14 | logs
15 | config/runtime*
16 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | Your contributions are essential to keeping bip.io fit and healthy. With tens of thousands of API's on the web ripe for integration, there's plenty of challenges and opportunity for you to be a valued community partner and for bip.io to make it worth your while. We want to keep it as easy as possible to contribute changes that
4 | get things working in your environment. There are a few guidelines that we
5 | need contributors to follow so that we can have a chance of keeping on
6 | top of thing and are all speaking the same language.
7 |
8 |
9 | ## Getting Started
10 |
11 | * Make sure you have a [GitHub account](https://github.com/signup/free)
12 | * Submit a ticket for your issue, assuming one does not already exist on the [repo issue tracker](https://github.com/bipio-server/bipio/issues).
13 | * Clearly describe the issue including steps to reproduce when it is a bug.
14 | * Make sure you fill in the earliest version that you know has the issue.
15 | * Fork the repository on GitHub
16 |
17 | ## Making Changes
18 |
19 | * Create a topic branch from where you want to base your work.
20 | * This is usually the master branch.
21 | * Only target release branches if you are certain your fix must be on that
22 | branch.
23 | * To quickly create a topic branch based on master; `git checkout -b
24 | fix/master/my_contribution master`. Please avoid working directly on the
25 | `master` branch.
26 | * Make commits of logical units.
27 | * Check for unnecessary whitespace with `git diff --check` before committing.
28 | * Make sure your commit messages are in the proper format.
29 |
30 | ````
31 | fixes #1
32 |
33 | Make the example in CONTRIBUTING imperative and concrete
34 |
35 | Without this patch applied the example commit message in the CONTRIBUTING
36 | document is not a concrete example. This is a problem because the
37 | contributor is left to imagine what the commit message should look like
38 | based on a description rather than an example. This patch fixes the
39 | problem by making the example concrete and imperative.
40 |
41 | The first line is a real life imperative statement with a ticket number
42 | from our issue tracker. The body describes the behavior without the patch,
43 | why this is a problem, and how the patch fixes the problem when applied.
44 | ````
45 |
46 | ## Submitting Changes
47 |
48 | * Push your changes to a topic branch in your fork of the repository.
49 | * Submit a pull request to the bipio repository in the bipio-server organization.
50 | * Update your Github issue to mark that you have submitted code and are ready for it to be reviewed, be sure to reference the issue number in your forked commit message (Status: Ready for Merge).
51 |
52 | ## Migrations
53 |
54 | [Migrations](http://en.wikipedia.org/wiki/Software_modernization) is the mechanism bip.io uses to upgrade itself when its software version changes. To create a migration, create the file `migrations/<% pkg.version%>/index.js`.
55 |
56 | [Example Migration](https://github.com/bipio-server/bipio/blob/master/migrations/0.2.50/index.js)
57 |
58 | ## Submitting Changes to Pods
59 |
60 | Changes to Pods (ie: bip-pod-? repositories in the Github bipio-server organization) should follow the same steps as above, however issues should be logged and tracked for each individual pod repository.
61 |
62 | ## Submitting New Pods for endorsement
63 |
64 | * Create a Pod under your own GitHub account named `bip-pod-{pod name}`
65 | * Submit a new issue in the [repo issue tracker](https://github.com/bipio-server/bipio/issues), detailing the new pod, some potential use cases (for testing), and a link to your repository
66 | * Your Pod repo will be installed and peer reviewed for scalability and security, and rolled into the [Official Pods List](https://github.com/bipio-server/bipio/wiki/Pod-List). If its generally useful, it may even ship with the server itself.
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # TESTS = tests/*.js tests/managers/*.js tests/models/*.js
2 | # TESTS = tests/*.js tests/managers/*.js
3 | # TESTS = tests/models/channel.js
4 | TESTS = tests/migrations/0.3.0.js
5 | REPORTER = dot
6 |
7 | install:
8 | ./tools/git-setup.sh
9 | @SYSTEM_TZ=`/usr/bin/env date +%Z` ./tools/setup.js
10 |
11 | test-install:
12 | @NODE_ENV=test ./tools/setup.js
13 |
14 | clean:
15 | rm ./config/*.json
16 |
17 | # node-inspector ::
18 | # --debug
19 | # --debug-brk
20 | test:
21 | @NODE_ENV=test ./node_modules/.bin/mocha \
22 | --reporter $(REPORTER) \
23 | --timeout 15000 \
24 | $(TESTS)
25 |
26 | test-cov: lib-cov
27 | @CONNECT_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
28 |
29 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: node-supervisor src/server.js
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **NOTICE:** This repository has been **DEPRECATED**. Do not use.
2 |
3 |
4 | =========
5 |
6 | Welcome to the [bip.io](https://bip.io) API Server (Snow 0.4)
7 |
8 | bip.io is Billion Instructions Per I/O - For People and Robots.
9 |
10 | Imagine you can send a single standard payload and have a limitless host of API's orchestrate at your command.
11 |
12 | That's what bip.io does.
13 |
14 | [](https://nodei.co/npm/bipio/)
15 |
16 | Follow on Twitter for regular news and updates.
17 |
18 | ----
19 |
20 | bip.io is a nodejs based web automation framework that runs 'bips'. A Bip is a web automation agent. A Bip can connect many different web services and perform useful work. It can act on your behalf or perform at your command.
21 |
22 | Bips can take actions in sequence or in parallel, and chain web services together as you like. They can be put to work via Web Hooks, Email or Trigger when something happens.
23 |
24 | bip.io can be installed alongside your existing open source app or prototype for out-of-band message transformation, feed aggregation, queuing, social network fanout or whatever you like, even on your [Raspberry Pi](http://www.raspberrypi.org/).
25 |
26 | This server software is a RESTful JSON API supporting account level namespacing and multiple domains ([fqdn](http://en.wikipedia.org/wiki/Fully_qualified_domain_name)) per account. Clients authenticate over HTTP Basic.
27 |
28 | bip.io is dynamic, flexible, fast, modular, opinionless and GPLv3 open source.
29 |
30 | Find out more in [the wiki](https://github.com/bipio-server/bipio/wiki).
31 |
32 |

33 |
34 |
35 | ### Pods
36 |
37 | Pods are the standalone service containers bip.io uses to encapsulate and standardize the world's API's. [Supported Services](https://github.com/bipio-server/bipio/wiki/Pod-List) are growing fast, and open source.
38 |
39 | This server ships with a few handy '[Pods](https://github.com/bipio-server/bipio/wiki/Pods)' which you can use right away - Email, Text/HTML/Markdown Templating, Flow Control, Syndication, Web Hooks and Time.
40 |
41 | Extra Pods can be found in the [master repository](https://github.com/bipio-server).
42 |
43 | To install a pod :
44 |
45 | npm install bip-pod-{pod-name}
46 | ./tools/pod-install.js -a {pod-name}
47 |
48 | And follow the instructions.
49 |
50 | Feel free to [craft your own](https://github.com/bipio-server/bipio/wiki/Pods#creating-pods).
51 |
52 | ## Requirements
53 |
54 | - [Node.js >= 0.10.15](http://nodejs.org) **API and graph resolver**
55 | - [MongoDB Server v2.6](http://www.mongodb.org) **data store**
56 | - [RabbitMQ](http://www.rabbitmq.com) **message broker**
57 |
58 | SMTP Bips are available out of the box with a Haraka plugin. Configs under [bipio-contrib/haraka](https://github.com/bipio-server/bipio-contrib).
59 |
60 | - [Haraka](https://github.com/baudehlo/Haraka)
61 |
62 | ## Installation
63 |
64 | ### docker (offical)
65 |
66 | [Find It Here](https://github.com/bipio-server/bipio-docker)
67 |
68 | #### npm (global)
69 |
70 | sudo npm install -g bipio
71 | bipio
72 |
73 | #### npm (local)
74 |
75 | sudo npm install bipio
76 | cd node_modules
77 | npm start
78 |
79 | #### git
80 |
81 | git clone git@github.com:bipio-server/bipio.git
82 | cd bipio
83 | npm install
84 | node . (or `npm start`)
85 |
86 | ### Visual Tools
87 |
88 | The bip.io server is a light weight headless API server and ships without a User Interface (UI). The official UI can be found on the [bip.io](https://bip.io) hosted platform. It's completely free, will run on all desktops and most tablets.
89 |
90 | [](https://vimeo.com/147186752)
91 |
92 | To learn about the UI, the [community knowledgebase](https://bip.uservoice.com/knowledgebase) is the best place to start.
93 |
94 | Although bip.io is a hosted cloud platform, you can still use it to manage your own bip.io server with a feature called ['Mounts'](https://bip.uservoice.com/knowledgebase/articles/764829-where-is-the-user-interface-for-my-open-source-bip)
95 |
96 | Sign in to [bip.io](https://bip.io) to mount your local install from your browser under My Account > Mounts > Create Mount.
97 |
98 | 
99 |
100 | #### Mounting Security Notes
101 |
102 | Be sure to answer **yes** to the SSL question during setup to install a self signed SSL certificate.
103 |
104 | `Enable SSL? This will let you mount this server from the https://bip.io dashboard :`
105 |
106 | This will avoid any browser security restrictions when mounting your server via the hosted website. You *must* visit your bipio server in a browser first and accept the self signed certificate, or the mount may not work eg : `https://localhost:5000/status`
107 |
108 | The UI is a thin client which is loaded entirely into your browser. Once loaded you can reach any bipio server your browser can connect to such as from behind any firewall, over VPN or IP tunnel etc.
109 |
110 | ## Technical Notes
111 |
112 | When setting bip.io up for the first time, the install process will enter interactive mode, saving the generated config to `config/default.json`.
113 |
114 | The location of the config file can be overrideen using the `NODE_CONFIG_DIR` environment variable.
115 |
116 | export NODE_CONFIG_DIR=
117 |
118 | Be sure to have a MongoDB server and Rabbit broker ready and available before install. Otherwise, follow the prompts during the install process to get a basically sane server running that you can play with.
119 |
120 | For Ubuntu users, a sample upstart script is supplied in `config/upstart_bip.conf` which should be copied to
121 | `/etc/init` and reconfigured to suit your environment.
122 |
123 | If you have a more complex deployment environment and the packaged sparse config doesn't suit, don't worry! Set the environment variable `BIPIO_SPARSE_CONFIG` to the path of your preferred config file, and it will use that instead.
124 |
125 | For a non-interactive setup (ie: make install without any user interaction) - set environment variable `HEADLESS=true`
126 |
127 | bip.io does not provide any load balancing beyond [node-cluster](http://nodejs.org/api/cluster.html). It can provide SSL termination but this is unsuitable for a production environment. If you need SSL termination this should be delegated to the forward proxy of your choice such as Nginx, Apache, HAProxy etc.
128 |
129 | ## Developing and Contributing
130 |
131 | A healthy contributor community is great for everyone! Take a look at the [Contribution Document](https://github.com/bipio-server/bipio/blob/master/CONTRIBUTING.md) to see how to get your changes merged in.
132 |
133 | ## Support
134 |
135 | Please log issues to the [repository issue tracker](https://github.com/bipio-server/bipio/issues) on GitHub.
136 |
137 | ## License
138 |
139 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
140 |
141 | http://www.apache.org/licenses/LICENSE-2.0
142 |
143 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
144 |
--------------------------------------------------------------------------------
/config/config.json-dist:
--------------------------------------------------------------------------------
1 | {
2 | "site_name" : "bip.io",
3 | "domain": "localhost",
4 | "domain_public" : "localhost:5000",
5 | "website_public": "http://localhost",
6 | "cdn_public": "http://localhost/static",
7 | "oembed_host": "http://localhost",
8 | "site_emitter": "https://bip.io",
9 | "proto_public": "http://",
10 | "crons" : {
11 | "stat" : "0 0 * * * *",
12 | "trigger" : "0 */15 * * * *",
13 | "expire" : "0 0 * * * *",
14 | "transforms_compact": "0 0 */8 * * *",
15 | "transforms_fetch": "0 0 */12 * * *"
16 | },
17 | "timezone" : "Asia/Tokyo",
18 | "server": {
19 | "port": 5000,
20 | "host" : "127.0.0.1",
21 | "sessionSecret" : "",
22 | "forks": 1,
23 | "smtp_bips" : false,
24 | "logLevel" : "info",
25 | "ssl" : {
26 | "key" : "",
27 | "cert" : ""
28 | }
29 | },
30 | "mailer": {
31 | "host": "localhost",
32 | "port": 25
33 | },
34 | "dbMongo": {
35 | "connect" : "localhost/bipio"
36 | },
37 | "rabbit": {
38 | "host" : "localhost",
39 | "vhost" : "",
40 | "auth": {
41 | "username": "guest",
42 | "password": "guest"
43 | },
44 | "exchanges": {
45 | "bastion_generic": {
46 | "queue_default": {
47 | "name": "queue_bastion",
48 | "config": {
49 | "durable": true,
50 | "autoDelete": false
51 | }
52 | },
53 | "route_default": "default",
54 | "cfg": {
55 | "type": "direct",
56 | "durable": true,
57 | "autoDelete": false,
58 | "confirm" : true
59 | }
60 | },
61 | "bastion_jobs": {
62 | "queue_default": {
63 | "name": "queue_jobs",
64 | "config": {
65 | "durable": true,
66 | "autoDelete": false
67 | }
68 | },
69 | "route_default": "default",
70 | "cfg": {
71 | "type": "direct",
72 | "durable": true,
73 | "autoDelete": false,
74 | "confirm" : true
75 | }
76 | },
77 | "bastion_ctl": {
78 | "queue_default": {
79 | "name": "queue_bastion_ctl",
80 | "config": {
81 | "durable": true,
82 | "autoDelete": true
83 | }
84 | },
85 | "route_default": "default",
86 | "cfg": {
87 | "type": "fanout",
88 | "durable": false,
89 | "autoDelete": false,
90 | "confirm" : true
91 | }
92 | }
93 | },
94 | "defaultExchange": "public_inbound"
95 | },
96 | "k": {},
97 | "jwtKey" : "",
98 | "modules" : {
99 | "auth": {
100 | "strategy" : "native"
101 | },
102 | "cdn" : {
103 | "strategy" : "fs",
104 | "config" : {
105 | "data_dir" : "data"
106 | }
107 | }
108 | },
109 | "pods": {
110 | "email" : {
111 | "mailer": {
112 | "host": "localhost"
113 | }
114 | },
115 | "templater" : {},
116 | "flow" : {},
117 | "syndication" : {},
118 | "http" : {},
119 | "time" : {},
120 | "math" : {},
121 | "html" : {},
122 | "crypto" : {}
123 | },
124 | "transforms" : {
125 | "fetch" : true,
126 | "syncFrom" : "https://api.bip.io"
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/config/defs.js:
--------------------------------------------------------------------------------
1 | var defs = {
2 |
3 | CONTENTTYPE_RSS : 'application/rss+xml',
4 | CONTENTTYPE_TEXT : 'text/plain',
5 | CONTENTTYPE_XML : 'text/xml',
6 | CONTENTTYPE_HTML : 'text/html',
7 | CONTENTTYPE_JSON : 'application/json',
8 | CONTENTTYPE_BINARY : 'application/octet-stream',
9 | CONTENTTYPE_CSV : 'application/csv',
10 | CONTENTTYPE_TSV : 'application/tsv',
11 |
12 | RESPONSE_OK : 'OK',
13 | RESPONSE_INPROCESS : 'IN_PROCESS',
14 | RESPONSE_ERROR : 'ERROR',
15 |
16 | DEFAULT_CACHE_EXPIRE_SECS : 10*60,
17 |
18 | ERR_CONSTRAINT : 'errConstraint',
19 |
20 | SIG_RESTART : 'bounce',
21 |
22 | JOB_USER_NOTIFICATION : 'userNotify',
23 |
24 | JOB_USER_STAT : 'userStat',
25 | JOB_USER_STAT_IN_MB : 'userStatInMB',
26 | JOB_USER_STAT_OUT_MB : 'userStatOutMB',
27 |
28 | // JOB_ATTACH_REFERER_ICON : 'attachBipRefererIcon',
29 |
30 | JOB_BIP_TRIGGER : 'bipTrigger',
31 |
32 | JOB_BIP_ACTIVITY : 'bipActivity',
33 |
34 | JOB_BIP_SET_DEFAULTS : 'transformDefaults',
35 |
36 | JOB_SET_DEFAULT_SPACE : 'spaceDefault',
37 |
38 | JOB_HEAP_DUMP : 'heapDump'
39 | };
40 |
41 | module.exports = defs;
--------------------------------------------------------------------------------
/config/upstart_bip.conf:
--------------------------------------------------------------------------------
1 | #
2 | # Copy this file to /etc/init/bip.conf and fix paths where needed to point
3 | # to your local installation
4 | #
5 | # then to start and stop :
6 | # start bip
7 | # stop bip
8 | #
9 | description "bip Startup Monitor"
10 | author "michael pearson"
11 |
12 | start on startup
13 | stop on shutdown
14 | console log
15 | respawn
16 |
17 | env APP_PATH="/path/to/bipio/src"
18 | env LOGFILE="/path/to/bipio/logs/server.log"
19 | env PIDFILE="/var/run/bip.pid"
20 | env USER=bdeploy
21 | env NODE_ENV="production"
22 |
23 | script
24 | export HOME="/path/to/bipio/"
25 |
26 | echo $$ > $PIDFILE
27 | chdir $HOME
28 | exec sudo -u $USER NODE_ENV=development /usr/bin/node $APP_PATH/server.js >> $LOGFILE 2>&1
29 | end script
30 |
31 | pre-start script
32 | # Date format same as (new Date()).toISOString() for consistency
33 | echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> $LOGFILE
34 | end script
35 |
36 | pre-stop script
37 | rm $PIDFILE
38 | echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> $LOGFILE
39 | end script
40 |
--------------------------------------------------------------------------------
/migrations/0.2.44/index.js:
--------------------------------------------------------------------------------
1 | // migration for https://github.com/bipio-server/bipio/pull/14
2 | var fs = require('fs'),
3 | Migration = {
4 | run : function(app, configPath, next) {
5 | var config = JSON.parse(fs.readFileSync(configPath)),
6 | repl = new RegExp('^/'),
7 | rootPath = GLOBAL.SERVER_ROOT + '/../',
8 | delta = false;
9 |
10 | if (0 === config.cdn.indexOf('/') && fs.existsSync(rootPath + config.cdn)) {
11 | console.info('Re-writing CDN config path');
12 | config.cdn = config.cdn.replace(repl, '');
13 | delta = true;
14 | }
15 |
16 | if (0 === config.datadir.indexOf('/') && fs.existsSync(rootPath + config.datadir)) {
17 | console.info('Re-writing Data Directory config path');
18 | config.datadir = config.datadir.replace(repl, '');
19 | delta = true;
20 | }
21 |
22 | if (delta) {
23 | fs.writeFile(configPath , JSON.stringify(config, null, 2), function(err) {
24 | if (err) {
25 | next(err, 'error');
26 | } else {
27 | console.info("\nConfig written to : " + configPath + "\n");
28 | next();
29 | }
30 | });
31 | } else {
32 | next('Nothing To Do');
33 | }
34 | }
35 | }
36 |
37 | module.exports = Migration;
--------------------------------------------------------------------------------
/migrations/0.2.50/index.js:
--------------------------------------------------------------------------------
1 | // Adds JWT Signing key
2 | var fs = require('fs'),
3 | crypto = require('crypto'),
4 | Migration = {
5 | run : function(app, configPath, next) {
6 | var config = JSON.parse(fs.readFileSync(configPath));
7 |
8 | crypto.randomBytes(48, function(ex, buf) {
9 | config.jwtKey = buf.toString('hex');
10 | fs.writeFile(configPath , JSON.stringify(config, null, 2), function(err) {
11 | if (err) {
12 | next(err, 'error');
13 | } else {
14 | console.info("\nConfig written to : " + configPath + "\n");
15 | next();
16 | }
17 | });
18 | });
19 | }
20 | }
21 |
22 | module.exports = Migration;
--------------------------------------------------------------------------------
/migrations/0.2.79/index.js:
--------------------------------------------------------------------------------
1 | // migration for https://github.com/bipio-server/bipio/pull/14
2 | var fs = require('fs'),
3 | Migration = {
4 | run : function(app, configPath, next) {
5 | var config = JSON.parse(fs.readFileSync(configPath)),
6 | rootPath = GLOBAL.SERVER_ROOT + '/../',
7 | delta = false;
8 |
9 | if (!config.modules) {
10 | config.modules = {};
11 | delta = true;
12 | }
13 |
14 | if (!config.modules.auth && config.auth) {
15 | config.modules.auth = {};
16 | config.modules.auth.strategy = config.auth.type;
17 | config.modules.auth.config = app._.clone(config.auth.config);
18 | delete config.auth;
19 | delta = true;
20 | }
21 |
22 | if (delta) {
23 | fs.writeFileSync(configPath , JSON.stringify(config, null, 2));
24 | console.info("\nConfig (for 0.2.79) syncronously written to : " + configPath + "\n");
25 | next();
26 | } else {
27 | next('Nothing To Do');
28 | }
29 | }
30 | }
31 |
32 | module.exports = Migration;
33 |
--------------------------------------------------------------------------------
/migrations/0.3.0/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | path = require('path'),
3 | Q = require('q'),
4 | minTime = new Date().getTime() - (30 * 24 * 60 * 60 * 1000),
5 | syndicationMigration = Q.defer(),
6 | soundcloudMigration = Q.defer(),
7 | promises = [ syndicationMigration.promise, soundcloudMigration.promise ],
8 |
9 | Migration = {
10 | run : function(app, configPath, next) {
11 |
12 | var config = JSON.parse(fs.readFileSync(configPath));
13 | // var config = jf.readFileSync(configPath);
14 |
15 |
16 | var rootPath = GLOBAL.SERVER_ROOT + '/../';
17 | var delta = false;
18 |
19 |
20 | config.cdn_public = config.cdn_public.replace(/\/img\/cdn/, '');
21 |
22 | if (!config.modules.hasOwnProperty("cdn")) {
23 | config.modules.cdn = {
24 | "strategy" : "fs",
25 | "config" : {
26 | "data_dir" : config.datadir
27 | }
28 | };
29 | console.log("**NOTICE** `cdn_public` URL has changed, please update any of your site cdn symlinks to point to : `" + config.modules.cdn.config.data_dir + "`");
30 | delta = true;
31 | }
32 |
33 | if (config.hasOwnProperty("datadir")) {
34 | delete config.datadir;
35 | delta = true;
36 | }
37 | if (config.hasOwnProperty("cdn")) {
38 | delete config.cdn;
39 | delta = true;
40 | }
41 |
42 | // Handle database migration
43 |
44 | if (config.pods.hasOwnProperty("syndication")) {
45 |
46 | app.dao.list('pod_syndication_track_subscribe', null, 100, 1, 'recent', { created: { $gt: minTime } }, function(err, oldModelName, results) {
47 |
48 | if (err) {
49 | syndicationMigration.reject(new Error(err));
50 | }
51 | else if (results.num_pages === 0) {
52 | console.log("...Syndication Migration finished.");
53 | syndicationMigration.resolve();
54 | }
55 | else {
56 | var syndPromises = [];
57 | console.log("Migrating Syndication subscription data from the last 30 days (if any)...");
58 |
59 | for (var index=1; index<=results.num_pages; index++) {
60 |
61 | (function(pageNum, syndicationMigration, isLastPage) {
62 | app.dao.list('pod_syndication_track_subscribe', null, 100, pageNum, 'recent', { created: { $gt: minTime } }, function(err, oldModelName, result) {
63 | for (var i=0; i= results.length) {
26 | next('Updated ' + count + ' Shares');
27 | }
28 |
29 | });
30 | })(results[i], i);
31 | }
32 | } else {
33 | next('Nothing To Do');
34 | }
35 | });
36 | }
37 | }
38 |
39 | module.exports = Migration;
--------------------------------------------------------------------------------
/migrations/0.4.16/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | Q = require('q'),
3 | Migration = {
4 | run : function(app, configPath, next) {
5 | var dao = app.dao,
6 | modelName = 'bip_share';
7 |
8 | dao.findFilter(
9 | modelName,
10 | {},
11 | function(err, results) {
12 | var UIDMap = {},r;
13 |
14 | if (err) {
15 | next(err);
16 | } else if (!results) {
17 | next('Nothing To Do');
18 | } else {
19 | for (var i = 0; i < results.length; i++) {
20 | r = results[i];
21 |
22 | if (!UIDMap[r.owner_id]) {
23 | UIDMap[r.owner_id] = [];
24 | }
25 |
26 | UIDMap[r.owner_id].push(r.id);
27 | }
28 |
29 | dao.findFilter(
30 | 'account',
31 | {
32 | 'id' : {
33 | $in : Object.keys(UIDMap)
34 | }
35 | },
36 | function(err, results) {
37 | if (err) {
38 | next(err);
39 | } else if (!results) {
40 | next('Shares Do Not Map To Local Users')
41 | } else {
42 | var owner;
43 | for (var i = 0; i < results.length; i++) {
44 | owner = results[i];
45 | dao.updateColumn(
46 | 'bip_share',
47 | {
48 | id : {
49 | '$in' : UIDMap[owner.id]
50 | }
51 | },
52 | {
53 | user_name : owner.username
54 | },
55 | function(err) {
56 | if (err) {
57 | next(err);
58 | } else {
59 | if (i >= results.length - 1) {
60 | next();
61 | }
62 | }
63 | }
64 | );
65 | }
66 | }
67 | }
68 | );
69 | }
70 | }
71 | );
72 | }
73 | }
74 |
75 | module.exports = Migration;
--------------------------------------------------------------------------------
/migrations/0.4.19/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | Q = require('q'),
3 | Migration = {
4 | run : function(app, configPath, next) {
5 | var dao = app.dao;
6 |
7 | dao.updateProperties(
8 | 'bip_share',
9 | {},
10 | {
11 | installs : 0
12 | },
13 | function(err) {
14 | next(err || 'Done')
15 | }
16 | );
17 | }
18 | }
19 |
20 | module.exports = Migration;
--------------------------------------------------------------------------------
/migrations/0.4.4/index.js:
--------------------------------------------------------------------------------
1 | // ENT-444
2 | var fs = require('fs'),
3 | Q = require('q'),
4 | Migration = {
5 | run : function(app, configPath, next) {
6 | var dao = app.dao,
7 | modelName = 'account',
8 | adminDefer = Q.defer();
9 | userDefer = Q.defer(),
10 | promises = [ adminDefer.promise, userDefer.promise ];
11 |
12 | Q.all(promises).then(
13 | function() {
14 | next();
15 | },
16 | function(err) {
17 | next(err)
18 | }
19 | );
20 |
21 | // set is_admin to user level 'admin'
22 | dao.updateColumn(
23 | modelName,
24 | {
25 | is_admin : true
26 | },
27 | {
28 | account_level : 'admin'
29 | },
30 | function(err, results) {
31 | console.log(arguments);
32 | if (err) {
33 | adminDefer.reject(err);
34 | } else {
35 | adminDefer.resolve();
36 | }
37 | }
38 | );
39 |
40 | // set !is_admin to user level 'user'
41 | dao.updateColumn(
42 | modelName,
43 | {
44 | is_admin : false
45 | },
46 | {
47 | account_level : 'user'
48 | },
49 | function(err, results) {
50 | console.log(arguments);
51 | if (err) {
52 | userDefer.reject(err);
53 | } else {
54 | userDefer.resolve();
55 | }
56 | }
57 | );
58 | }
59 | }
60 |
61 | module.exports = Migration;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Michael Pearson",
3 | "name": "bipio",
4 | "version": "0.5.0",
5 | "scripts": {
6 | "start": "node src/server.js >> logs/server.log &",
7 | "test": "make test",
8 | "install": "make install"
9 | },
10 | "main": "src/server.js",
11 | "license": "Apache-2.0",
12 | "bin": {
13 | "bipio": "./src/server.js",
14 | "bipio-setup": "./tools/setup.js",
15 | "bipio-token-regen": "./tools/token_regen.js",
16 | "bipio-pod-install": "./tools/pod-install.js",
17 | "bipio-trigger": "./tools/bip-trigger.js",
18 | "bipio-expire": "./tools/bip-expire.js",
19 | "bipio-generate-hub-stats": "./tools/generate-hub-stats.js"
20 | },
21 | "description": "API and graph resolver for the bipio content pipeline.",
22 | "homepage": "https://bip.io",
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/bipio-server/bipio"
26 | },
27 | "engines": {
28 | "node": ">=v0.10.2"
29 | },
30 | "dependencies": {
31 | "JSONPath": "^0.10.0",
32 | "amqp": ">=0.1.3",
33 | "async": "0.1.18",
34 | "base-converter": "1.1.2",
35 | "bcrypt": ">=0.5.0",
36 | "bip-pod": ">=0.4.14",
37 | "bip-pod-crypto": ">=0.0.1",
38 | "bip-pod-email": ">=0.0.1",
39 | "bip-pod-flow": ">=0.0.1",
40 | "bip-pod-html": ">=0.0.1",
41 | "bip-pod-http": ">=0.0.1",
42 | "bip-pod-math": ">=0.0.1",
43 | "bip-pod-syndication": ">=0.4.5",
44 | "bip-pod-templater": ">=0.0.1",
45 | "bip-pod-time": ">=0.0.1",
46 | "body-parser": "~1.13.2",
47 | "clone": ">=0.1.0",
48 | "commander": ">=2.0.0",
49 | "config": "0.4.36",
50 | "connect": "2.30.2",
51 | "connect-mongo": "0.8.2",
52 | "cookie-parser": "^1.0.1",
53 | "cron": ">=1.0.1",
54 | "dateformat": "1.0.7-1.2.3",
55 | "datejs": ">=0.0.2",
56 | "errorhandler": "^1.1.1",
57 | "express": ">=4.0.0",
58 | "express-session": "^1.0.4",
59 | "extend": "^2.0.0",
60 | "favitest": "^1.0.3",
61 | "html-md": "^3.0.2",
62 | "htmlencode": ">=0.0.1",
63 | "htmlparser2": ">=3.4.0",
64 | "imagemagick": ">=0.1.3",
65 | "inquirer": ">=0.2.4",
66 | "ipaddr.js": ">=0.1.2",
67 | "json-middleware": "^1.0.2",
68 | "jsonwebtoken": ">=1.0.0",
69 | "ldapjs": "^0.7.1",
70 | "lodash": "^3.2.0",
71 | "marked": "^0.3.2",
72 | "method-override": "^1.0.0",
73 | "mime": "^1.2.11",
74 | "mkdirp": ">=0.3.5",
75 | "moment": "^2.8.4",
76 | "moment-timezone": ">=0.3.0",
77 | "mongoose": "4.2.3",
78 | "multer": "0.1.8",
79 | "node-fs": "^0.1.7",
80 | "node-uuid": "1.3.3",
81 | "passport": ">=0.1.15",
82 | "pkgcloud": ">=1.1.0",
83 | "posix-getopt": "1.1.0",
84 | "q": "^1.0.1",
85 | "request": ">=2.2.9",
86 | "rimraf": ">=2.2.6",
87 | "rrecur": ">=2.0.0",
88 | "sleep": ">=1.2.0",
89 | "sprintf": ">=0.1.1",
90 | "ssl-root-cas": "^1.1.7",
91 | "sugar": "^1.4.1",
92 | "sync-exec": "0.6.2",
93 | "temp": ">=0.5.0",
94 | "time": ">=0.9.2",
95 | "tldtools": ">=0.0.6",
96 | "underscore": ">=1.5.2",
97 | "validator": "1.5.1",
98 | "winston": "1.0.0"
99 | },
100 | "devDependencies": {
101 | "should": "*",
102 | "mocha": "*",
103 | "dox": "*"
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/lib/rabbit.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * AMQP Transport wrapper
24 | *
25 | */
26 | var amqp = require('amqp'),
27 | app = GLOBAL.app;
28 |
29 | function Rabbit(cfg, next) {
30 | var self = this;
31 | this.exchanges = [];
32 | this.queues = [];
33 | this.cfg = cfg;
34 | var opt = {
35 | host: cfg.host,
36 | login: cfg.auth.username,
37 | password : cfg.auth.password,
38 | noDelay : true
39 | };
40 |
41 | if ('' !== cfg.vhost) {
42 | opt.vhost = cfg.vhost;
43 | }
44 |
45 | this.amqpConn = amqp.createConnection(opt,
46 | {
47 | defaultExchangeName: cfg.defaultExchange
48 | }
49 | );
50 |
51 | this.amqpConn.connectionStatus = null;
52 |
53 | // Setup our preconfigured exchanges, queues and routes
54 | this.amqpConn.on(
55 | 'ready',
56 | function() {
57 | self.amqpConn.connectionStatus = 'connected';
58 | for (xName in cfg.exchanges) {
59 | self.exchanges[xName] = self.amqpConn.exchange(
60 | xName,
61 | cfg.exchanges[xName].cfg,
62 | function() {
63 | var exchange = this;
64 | app.logmessage('RABBIT:X:' + this.name + ':UP');
65 | var xStruct = cfg.exchanges[this.name];
66 |
67 | // create default queue for this exchange
68 | self.queues[xStruct.queue_default.name] = self.amqpConn.queue(
69 | xStruct.queue_default.name,
70 | xStruct.queue_default.config,
71 | function() {
72 | this.bind(exchange, xStruct.route_default);
73 | app.logmessage('RABBIT:Q:' + (undefined !== next ? 'PUBSUB' : 'PUB') + this.name + ':UP' );
74 | if (next) {
75 | next(this.name);
76 | }
77 | });
78 | });
79 | }
80 | });
81 |
82 | this.amqpConn.on('connect', function() {
83 | app.logmessage('RABBIT:Connected');
84 | });
85 |
86 | this.amqpConn.on('error', function(err) {
87 | self.amqpConn.connectionStatus = null;
88 | app.logmessage('RABBIT:' + err, 'error');
89 | });
90 | }
91 |
92 | Rabbit.prototype.produce = function(xName, route, payload, cb) {
93 | this.exchanges[xName].publish(route, JSON.stringify(payload), {}, cb);
94 | }
95 |
96 | Rabbit.prototype.producePublic = function(payload, cb) {
97 | this.produce('bastion_generic', 'default', payload, cb);
98 | }
99 |
100 | Rabbit.prototype.produceJob = function(payload, cb) {
101 | this.produce('bastion_jobs', 'default', payload, cb);
102 | }
103 |
104 | Rabbit.prototype.getQueueByName = function(queueName) {
105 | return this.queues[queueName];
106 | }
107 |
108 | Rabbit.prototype.disconnect = function() {
109 | this.amqpConn.disconnect();
110 | this.amqpConn.connectionStatus = null;
111 | app.logmessage('RABBIT:DISCONNECTED');
112 | }
113 |
114 | module.exports = Rabbit;
115 |
--------------------------------------------------------------------------------
/src/lib/step.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011 Tim Caswell
3 |
4 | MIT License
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | // Inspired by http://github.com/willconant/flow-js, but reimplemented and
26 | // modified to fit my taste and the node.JS error handling system.
27 | function Step() {
28 | var steps = Array.prototype.slice.call(arguments),
29 | pending, counter, results, lock;
30 |
31 | // Define the main callback that's given as `this` to the steps.
32 | function next() {
33 | counter = pending = 0;
34 |
35 | // Check if there are no steps left
36 | if (steps.length === 0) {
37 | // Throw uncaught errors
38 | if (arguments[0]) {
39 | throw arguments[0];
40 | }
41 | return;
42 | }
43 |
44 | // Get the next step to execute
45 | var fn = steps.shift();
46 | results = [];
47 |
48 | // Run the step in a try..catch block so exceptions don't get out of hand.
49 | try {
50 | lock = true;
51 | var result = fn.apply(next, arguments);
52 | } catch (e) {
53 | // Pass any exceptions on through the next callback
54 | next(e);
55 | }
56 |
57 | if (counter > 0 && pending == 0) {
58 | // If parallel() was called, and all parallel branches executed
59 | // synchronously, go on to the next step immediately.
60 | next.apply(null, results);
61 | } else if (result !== undefined) {
62 | // If a synchronous return is used, pass it to the callback
63 | next(undefined, result);
64 | }
65 | lock = false;
66 | }
67 |
68 | // Add a special callback generator `this.parallel()` that groups stuff.
69 | next.parallel = function () {
70 | var index = 1 + counter++;
71 | pending++;
72 |
73 | return function () {
74 | pending--;
75 | // Compress the error from any result to the first argument
76 | if (arguments[0]) {
77 | results[0] = arguments[0];
78 | }
79 | // Send the other results as arguments
80 | results[index] = arguments[1];
81 | if (!lock && pending === 0) {
82 | // When all parallel branches done, call the callback
83 | next.apply(null, results);
84 | }
85 | };
86 | };
87 |
88 | // Generates a callback generator for grouped results
89 | next.group = function () {
90 | var localCallback = next.parallel();
91 | var counter = 0;
92 | var pending = 0;
93 | var result = [];
94 | var error = undefined;
95 |
96 | function check() {
97 | if (pending === 0) {
98 | // When group is done, call the callback
99 | localCallback(error, result);
100 | }
101 | }
102 | process.nextTick(check); // Ensures that check is called at least once
103 |
104 | // Generates a callback for the group
105 | return function () {
106 | var index = counter++;
107 | pending++;
108 | return function () {
109 | pending--;
110 | // Compress the error from any result to the first argument
111 | if (arguments[0]) {
112 | error = arguments[0];
113 | }
114 | // Send the other results as arguments
115 | result[index] = arguments[1];
116 | if (!lock) { check(); }
117 | };
118 | };
119 | };
120 |
121 | // Start the engine an pass nothing to the first step.
122 | next();
123 | }
124 |
125 | // Tack on leading and tailing steps for input and output and return
126 | // the whole thing as a function. Basically turns step calls into function
127 | // factories.
128 | Step.fn = function StepFn() {
129 | var steps = Array.prototype.slice.call(arguments);
130 | return function () {
131 | var args = Array.prototype.slice.call(arguments);
132 |
133 | // Insert a first step that primes the data stream
134 | var toRun = [function () {
135 | this.apply(null, args);
136 | }].concat(steps);
137 |
138 | // If the last arg is a function add it as a last step
139 | if (typeof args[args.length-1] === 'function') {
140 | toRun.push(args.pop());
141 | }
142 |
143 |
144 | Step.apply(null, toRun);
145 | }
146 | }
147 |
148 |
149 | // Hook into commonJS module systems
150 | if (typeof module !== 'undefined' && "exports" in module) {
151 | module.exports = Step;
152 | }
--------------------------------------------------------------------------------
/src/models/account.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 | var BipModel = require('./prototype.js').BipModel;
21 |
22 | var Account = Object.create(BipModel);
23 |
24 | GLOBAL.DEFS.ACCOUNT_LEVEL = {
25 | USER : 'user',
26 | ADMIN : 'admin'
27 | }
28 |
29 | Account.id = '';
30 | Account.name = '';
31 | Account.username = '';
32 | Account.email_account = '';
33 | Account.account_level = GLOBAL.DEFS.ACCOUNT_LEVEL.USER;
34 |
35 | Account.compoundKeyConstraints = {
36 | username : 1,
37 | email_account : 1
38 | };
39 |
40 | Account.entityName = 'account';
41 | Account.entitySchema = {
42 | id: {
43 | type: String,
44 | renderable: true,
45 | writable: false
46 | },
47 |
48 | username: {
49 | type: String,
50 | renderable: true,
51 | writable: false
52 | },
53 |
54 | name: {
55 | type: String,
56 | renderable: true,
57 | writable: true
58 | },
59 |
60 | email_account: {
61 | type: String,
62 | renderable: true,
63 | writable: false
64 | },
65 |
66 | created : {
67 | type: Number,
68 | renderable: true,
69 | writable: false
70 | },
71 |
72 | last_session : {
73 | type: Number,
74 | renderable: true,
75 | writable: false
76 | },
77 |
78 | account_level : {
79 | type : String,
80 | renderable : true,
81 | writable : false,
82 | default : GLOBAL.DEFS.ACCOUNT_LEVEL.USER,
83 | validate : [
84 | {
85 | validator : function(val, next) {
86 | next(
87 | -1 !== app._.values(GLOBAL.DEFS.ACCOUNT_LEVEL).indexOf(val)
88 | );
89 | },
90 | msg : 'Invalid Account Level'
91 | }
92 | ]
93 | }
94 | };
95 | /*
96 | // lazy loader
97 | Account.collections = {};
98 |
99 | Account._load = function(collection, next) {
100 | var self = this;
101 |
102 | if (!this.collections[collection]) {
103 | this.dao.findFilter(
104 | collection,
105 | {
106 | owner_id : this.account.id
107 | },
108 | function(err, result) {
109 | if (err) {
110 | next(err);
111 | } else {
112 | self.collections[collection] = result;
113 | }
114 | }
115 | );
116 |
117 | } else {
118 | next(false, this.collections[collection]);
119 | }
120 | };
121 |
122 | Account.getSetting = function(name, next) {
123 | this._load('account_option', function(err, settings) {
124 | if (settings && settings.length) {
125 | next(err, settings[0][name])
126 |
127 | } else {
128 | next(err);
129 | }
130 | });
131 | };
132 |
133 | Account.getSettings = function(next) {
134 | this._load('account_option', function(err, settings) {
135 | if (settings && settings.length) {
136 | next(err, settings[0])
137 |
138 | } else {
139 | next(err);
140 | }
141 | });
142 | };
143 |
144 | Account.getName : function() {
145 | return this.name;
146 | };
147 |
148 | Account.getUsername : function() {
149 | return this.username;
150 | };
151 |
152 | Account.getDomains = function(next) {
153 | this._load('domain', next);
154 | };
155 |
156 | Account.getChannels = function(next) {
157 | this._load('channel', next);
158 | };
159 |
160 | Account.getTimezone = function(next) {
161 | return this.getSetting('timezone', next);
162 | };
163 |
164 | //
165 | Account.getDefaultDomain = function(next) {
166 | var self = this;
167 | if (this.defaultDomain) {
168 | next(false, this.defaultDomain);
169 | } else {
170 | this.getDomains(function(err, domains) {
171 | var defaultDomain;
172 | if (err) {
173 | next(err);
174 | } else {
175 | for (var i = 0; i < domains.length; i++) {
176 | if ('vanity' === domains[i].type) {
177 | self.defaultDomain = domains[i];
178 | }
179 | }
180 | }
181 | });
182 | }
183 | };
184 |
185 | //
186 | Account.getDefaultDomainStr = function(next) {
187 | this.getDefaultDomain(
188 | function(err, domain) {
189 | if (err) {
190 | next(err);
191 | } else {
192 | next(false, GLOBAL.CFG.proto_public + domain.name
193 | }
194 | }
195 | );
196 | }
197 | */
198 |
199 | module.exports.Account = Account;
200 |
--------------------------------------------------------------------------------
/src/models/account_activity.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * Rolling account activity
24 | *
25 | */
26 | var AccountActivityModel = require('./prototype.js').BipModel,
27 | AccountActivity = Object.create(AccountActivityModel);
28 |
29 | AccountActivity.entityName = 'stats_account';
30 | AccountActivity.entitySchema = {
31 | id: { // day
32 | type: String,
33 | renderable: true,
34 | writable: false
35 | },
36 | users_new : {
37 | type: String,
38 | renderable: true,
39 | writable: true
40 | },
41 | users_signin : {
42 | type: String,
43 | renderable: true,
44 | writable: true
45 | },
46 |
47 | // by bip type
48 | new_bip_breakdown : {
49 | type : Object,
50 | renderable: true,
51 | writable: true
52 | },
53 | new_bips_total: {
54 | type: Integer,
55 | renderable: true,
56 | writable: true
57 | },
58 |
59 | // by channel action
60 | new_channel_breakdown : {
61 | type : Object,
62 | renderable: true,
63 | writable: true
64 | },
65 | new_channels_total: {
66 | type: Integer,
67 | renderable: true,
68 | writable: true
69 | },
70 |
71 | channels_unverified: {
72 | type: Integer,
73 | renderable: true,
74 | writable: true
75 | },
76 |
77 |
78 | new_domains_total: {
79 | type: Integer,
80 | renderable: true,
81 | writable: true
82 | },
83 |
84 | delivered_bip_inbound: {
85 | type: Integer,
86 | renderable: true,
87 | writable: true
88 | },
89 | delivered_channel_outbound : {
90 | type: Array,
91 | renderable: true,
92 | writable: true
93 | },
94 |
95 | traffic_inbound: {
96 | type: Integer,
97 | renderable: true,
98 | writable: true
99 | },
100 | traffic_outbound: {
101 | type: Integer,
102 | renderable: true,
103 | writable: true
104 | },
105 |
106 | demographic_users_male: {
107 | type: Integer,
108 | renderable: true,
109 | writable: true
110 | },
111 |
112 | demographic_users_female: {
113 | type: Integer,
114 | renderable: true,
115 | writable: true
116 | },
117 |
118 | demographic_users_unknown: {
119 | type: Integer,
120 | renderable: true,
121 | writable: true
122 | }
123 | };
124 |
125 | module.exports.AccountActivity = AccountActivity;
126 |
--------------------------------------------------------------------------------
/src/models/account_auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | *
20 |
21 | */
22 | var bcrypt = require('bcrypt'),
23 | crypto = require('crypto'),
24 | BipModel = require('./prototype.js').BipModel;
25 |
26 | var AccountAuth = Object.create(BipModel);
27 |
28 | function strCryptSync(str) {
29 | return bcrypt.hashSync(str, bcrypt.genSaltSync(10));
30 | }
31 |
32 | function strCryptCmpSync(taintedClear, localHash) {
33 | return bcrypt.compareSync(taintedClear, localHash);
34 | }
35 |
36 | function AESCrypt(value) {
37 | var key, keyVersion,
38 | iv = crypto.randomBytes(32).toString('hex').substr(0, 16);
39 | // get latest key
40 | for (keyVersion in CFG.k) {
41 | key = CFG.k[keyVersion];
42 | }
43 |
44 | var cipher = crypto.createCipheriv('aes-256-cbc', key, iv),
45 | crypted = cipher.update(value, 'ascii', 'base64') + cipher.final('base64');
46 | cryptEncoded = new Buffer(keyVersion + iv + crypted).toString('base64');
47 |
48 | return cryptEncoded;
49 | }
50 |
51 | function AESDecrypt(cryptedStr, autoPadding) {
52 | var crypted = new Buffer(cryptedStr, 'base64').toString('utf-8');
53 | var keyVersion = crypted.substr(0, 1),
54 | iv = crypted.substr(1, 16),
55 | key = CFG.k[keyVersion],
56 | cypher = crypted.substr(17);
57 |
58 | var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
59 |
60 | if (!autoPadding) {
61 | autoPadding = false;
62 | }
63 | decipher.setAutoPadding(autoPadding);
64 |
65 | var decrypted = (decipher.update(cypher, 'base64', 'ascii') + decipher.final('ascii'));
66 | return decrypted;
67 | }
68 |
69 | function pwHash(pwValue) {
70 | var crypted;
71 | // tokens use AES
72 | if (this.type !== 'login_primary') {
73 | crypted = AESCrypt(pwValue);
74 | // or seeded crypt
75 | } else {
76 | crypted = strCryptSync(pwValue);
77 | }
78 | return crypted;
79 | }
80 |
81 | function cryptSave(value) {
82 | if (value) {
83 | var crypted = value;
84 |
85 | // passwords get
86 | if (this.type == 'login_primary' || this.type == 'login_sub') {
87 | crypted = strCryptSync(value);
88 | //app.logmessage('Trying to write login primary to account_auth [' + this.id + ']', 'error');
89 | //throw new Error('Bad Type');
90 | } else if (this.type !== 'token_invite') {
91 | crypted = AESCrypt(value);
92 | }
93 |
94 | return crypted;
95 | } else {
96 | return value;
97 | }
98 | }
99 |
100 | function _encStr(s, toUnicode) {
101 | var json = JSON.stringify(s);
102 | return toUnicode ? json : json.replace(/[\u007f-\uffff]/g,
103 | function(c) {
104 | return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4);
105 | }
106 | );
107 | }
108 |
109 | function cryptSaveObj(value) {
110 | if (value) {
111 | //var strVal = (new Buffer(JSON.stringify(value), 'utf-8' )).toString('ascii')
112 | //return cryptSave(JSON.stringify(strVal));
113 | var strVal = _encStr(value, false)
114 | return cryptSave(JSON.stringify(strVal));
115 | } else {
116 | return value;
117 | }
118 | }
119 |
120 | AccountAuth.id = '';
121 | AccountAuth.username = '';
122 | AccountAuth.owner_id = '';
123 | // enum 'login_primary', 'login_sub', 'token', 'token_invite', 'oauth', 'oauth_app', 'api_token'
124 | AccountAuth.type = '';
125 | AccountAuth.password = '';
126 |
127 | AccountAuth.oauth_provider = ''; // pod/provider name, where type = 'oauth'
128 | AccountAuth.oauth_refresh = ''; // AES refresh token, where type = 'oauth'
129 | AccountAuth.oauth_profile = ''; // AES serialized profile, where type = 'oauth'
130 |
131 | AccountAuth.entityName = 'account_auth';
132 | AccountAuth.entitySchema = {
133 | id: {
134 | type: String,
135 | index: true,
136 | renderable: true,
137 | writable: false
138 | },
139 | type: {
140 | type: String,
141 | index: true,
142 | renderable: true,
143 | writable: false
144 | },
145 | password: {
146 | type: String,
147 | renderable: false,
148 | writable: false,
149 | set : cryptSave
150 | },
151 | username: {
152 | type: String,
153 | renderable: false,
154 | writable: false,
155 | set : cryptSave
156 | },
157 | key: {
158 | type: String,
159 | renderable: false,
160 | writable: false,
161 | set : cryptSave
162 | },
163 | owner_id : {
164 | type: String,
165 | index: true,
166 | renderable: true,
167 | writable: false
168 | },
169 | auth_provider: {
170 | type: String,
171 | renderable: true,
172 | writable: false
173 | },
174 | oauth_provider: {
175 | type: String,
176 | renderable: true,
177 | writable: false
178 | },
179 | oauth_refresh: {
180 | type: String,
181 | renderable: true,
182 | writable: false,
183 | set : cryptSave
184 | },
185 | oauth_token_expire : {
186 | type : Number,
187 | renderable : false,
188 | writable : false,
189 | set : function(value) {
190 | if (value) {
191 | return (new Date()).getTime() + (value * 1000)
192 | } else {
193 | return value;
194 | }
195 | }
196 | },
197 | oauth_profile: {
198 | type: Object,
199 | renderable: true,
200 | writable: false,
201 | set : cryptSaveObj
202 | }
203 | };
204 |
205 | AccountAuth.hash = function(value) {
206 | return pwHash(value);
207 | }
208 |
209 | AccountAuth.cmpPassword = function(passwordTainted) {
210 | var password = this.getPassword().replace(/^\s+|\s+$/g, "");
211 |
212 | // compare hash
213 | /* disabled
214 | if (this.type == 'login_primary') {
215 | return bcrypt.compareSync(passwordTainted, password);
216 | */
217 | // AES
218 | if (this.type == 'token') {
219 | return passwordTainted == password;
220 | }
221 | return false;
222 | };
223 |
224 | // gets the password, if it's async then try to decrypt
225 | AccountAuth.getPassword = function() {
226 | // AES
227 | if (this.type == 'token') {
228 | return AESDecrypt(this.password).substr(0,32);
229 | } else {
230 | // return this.password;
231 | if (this.password) {
232 | return AESDecrypt(this.password, true);
233 | } else {
234 | return this.password;
235 | }
236 | }
237 | };
238 |
239 | AccountAuth.getUsername = function() {
240 | if (this.username) {
241 | return AESDecrypt(this.username, true);
242 | } else {
243 | return;
244 | }
245 | };
246 |
247 | AccountAuth.getKey = function() {
248 | if (this.key) {
249 | return AESDecrypt(this.key, true);
250 | } else {
251 | return;
252 | }
253 | };
254 |
255 | AccountAuth.getOAuthRefresh = function() {
256 | if (this.oauth_refresh) {
257 | return AESDecrypt(this.oauth_refresh, true);
258 | } else {
259 | return null;
260 | }
261 | }
262 |
263 | // gets oauth profile, handles legacy (json string)
264 | // and new object translation
265 | AccountAuth.getOauthProfile = function() {
266 | var profile = AESDecrypt(this.oauth_profile, true);
267 | if (app.helper.isObject(profile)) {
268 | return profile;
269 | } else {
270 | try {
271 | return JSON.parse(profile);
272 | } catch (e) {
273 | return 'Profile Not Available';
274 | }
275 | }
276 | }
277 |
278 | module.exports.AccountAuth = AccountAuth;
--------------------------------------------------------------------------------
/src/models/account_log.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * Rolling account activity
24 | *
25 | */
26 | var AccountLogModel = require('./prototype.js').BipModel,
27 | AccountLog = Object.create(AccountLogModel);
28 |
29 | AccountLog.codes = {
30 |
31 | 'channel_verify_email' : 'Email Verification Sent',
32 | 'channel_verify_email_yes' : 'Email Verified',
33 | 'channel_verify_email_no' : 'Email Opted Out',
34 |
35 | 'channel_create' : 'Channel Created',
36 | 'channel_deliver' : 'Message Delivered to Channel',
37 |
38 | 'bip_create' : 'Bip Created',
39 | 'bip_recieve' : 'Message received by Bip',
40 | 'bip_expired' : 'Bip Expired (Paused)'
41 | }
42 |
43 | AccountLog.entityName = 'account_log';
44 | AccountLog.entitySchema = {
45 | id: { // log
46 | type: String,
47 | renderable: true,
48 | writable: false
49 | },
50 | owner_id : {
51 | type: String,
52 | renderable: false,
53 | writable: false
54 | },
55 | code : {
56 | type: String,
57 | renderable: true,
58 | writable: false
59 | },
60 | description : {
61 | type: String,
62 | renderable: true,
63 | writable: false
64 | },
65 | content : {
66 | type: String,
67 | renderable: true,
68 | writable: false
69 | },
70 | 'public' : {
71 | type: String,
72 | renderable: false,
73 | writable: false
74 | },
75 | created : {
76 | type: Number,
77 | renderable: true,
78 | writable: false
79 | }
80 | };
81 |
82 | function setDescription(code) {
83 | this.description = AccountLog.codes[code];
84 | }
85 |
86 | Bip.entitySetters = {
87 | 'code' : setDescription
88 | };
89 |
90 | module.exports.AccountLog = AccountLog;
91 |
--------------------------------------------------------------------------------
/src/models/bip_log.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * Bip Activity + Error Log
24 | *
25 | */
26 | var BipLogModel = require('./prototype.js').BipModel,
27 | BipLog = Object.create(BipLogModel);
28 |
29 | BipLog.codes = {
30 | 'bip_create' : 'Created',
31 | 'bip_deleted_auto' : 'Expired (Deleted)',
32 | 'bip_deleted_manual' : 'Deleted',
33 | 'bip_recieve' : 'Message Received',
34 | 'bip_paused_auto' : 'Expired (Paused)',
35 | 'bip_paused_manual' : 'Manually Paused',
36 | 'bip_share' : 'Config Shared',
37 | 'bip_unshare' : 'Config Un-Shared',
38 | 'bip_invoke' : 'Invoked',
39 | 'bip_channnel_error' : 'Channel Error'
40 | }
41 |
42 | BipLog.entityName = 'bip_log';
43 | BipLog.entitySchema = {
44 | id: { // log
45 | type: String,
46 | renderable: true,
47 | writable: false
48 | },
49 | owner_id : {
50 | type: String,
51 | renderable: false,
52 | index: true,
53 | writable: false
54 | },
55 | bip_id : {
56 | type: String,
57 | renderable: false,
58 | index: true,
59 | writable: false
60 | },
61 | transaction_id : {
62 | type: String,
63 | renderable: true,
64 | writable: false
65 | },
66 | code : {
67 | type: String,
68 | renderable: true,
69 | writable: false,
70 | set : function(code) {
71 | if (BipLog.codes[code]) {
72 | this.message = BipLog.codes[code];
73 | }
74 | return code;
75 | }
76 | },
77 | source : { // action source
78 | type: String,
79 | renderable: true,
80 | writable: false
81 | },
82 | message : {
83 | type: String,
84 | renderable: true,
85 | writable: false
86 | },
87 | data : {
88 | type: Object,
89 | renderable: false,
90 | writable: false
91 | },
92 | created : {
93 | type: Number,
94 | renderable: true,
95 | writable: false
96 | }
97 | };
98 |
99 | module.exports.BipLog = BipLog;
100 |
--------------------------------------------------------------------------------
/src/models/bip_share.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * Shared Bip hubs
24 | *
25 | */
26 | var BipShare = Object.create(require('./prototype.js').BipModel);
27 |
28 | function escapeDot(val) {
29 | return val.replace(/\./g, '\u0001');
30 | }
31 |
32 | function unEscapeDot(val) {
33 | return val.replace(/\u0001/g, '.');
34 | }
35 |
36 | BipShare.entityName = 'bip_share';
37 | BipShare.entitySchema = {
38 | id: { // day
39 | type: String,
40 | renderable: true,
41 | writable: false
42 | },
43 | bip_id : {
44 | type: String,
45 | renderable: false,
46 | writable: false
47 | },
48 |
49 | type : {
50 | type: String,
51 | renderable: true,
52 | writable: true
53 | },
54 |
55 | name : {
56 | type: String,
57 | renderable: true,
58 | writable: true
59 | },
60 |
61 | slug : {
62 | type: String,
63 | renderable: true,
64 | writable: true
65 | },
66 |
67 | note : {
68 | type: String,
69 | renderable: true,
70 | writable: true
71 | },
72 |
73 | icon : {
74 | type: String,
75 | renderable: true,
76 | writable: true
77 | },
78 |
79 | config : {
80 | type: Object,
81 | renderable: true,
82 | writable: true
83 | },
84 |
85 | owner_id : {
86 | type: String,
87 | renderable: true,
88 | writable: false
89 | },
90 | owner_name : {
91 | type: String,
92 | renderable: true,
93 | writable: false
94 | },
95 | user_name : {
96 | type: String,
97 | renderable: true,
98 | writable: false
99 | },
100 | manifest : {
101 | type: Array,
102 | renderable: true,
103 | writable: false
104 | },
105 | manifest_hash : {
106 | type: String,
107 | renderable: true,
108 | writable: false
109 | },
110 | hub : {
111 | type: Object,
112 | renderable: true,
113 | writable: false,
114 | set : function(hub) {
115 | var newSrc, newCid;
116 |
117 | // normalize
118 | for (var src in hub) {
119 |
120 | newSrc = escapeDot(src);
121 | hub[newSrc] = hub[src];
122 |
123 | if (newSrc !== src) {
124 | delete hub[src];
125 | }
126 |
127 | if ( hub.hasOwnProperty(newSrc) ) {
128 | for (var cid in hub[newSrc].transforms) {
129 |
130 | newCid = escapeDot(cid);
131 | hub[newSrc].transforms[newCid] = hub[newSrc].transforms[cid];
132 | if (newCid !== cid) {
133 | delete hub[newSrc].transforms[cid];
134 | }
135 |
136 | }
137 | }
138 | }
139 |
140 | // parse
141 | for (var src in hub) {
142 | if (hub.hasOwnProperty(src)) {
143 | for (var cid in hub[src].transforms) {
144 | if (hub[src].transforms.hasOwnProperty(cid)) {
145 | for (var k in hub[src].transforms[cid]) {
146 | hub[src].transforms[cid][k] = hub[src].transforms[cid][k].trim();
147 | }
148 | }
149 | }
150 | }
151 | }
152 |
153 | return hub;
154 | },
155 | customGetter : function(hub) {
156 | var newSrc, newCid;
157 |
158 | // normalize
159 | for (var src in hub) {
160 |
161 | newSrc = unEscapeDot(src);
162 | hub[newSrc] = hub[src];
163 |
164 | if (newSrc !== src) {
165 | delete hub[src];
166 | }
167 |
168 | if ( hub.hasOwnProperty(newSrc) ) {
169 | for (var cid in hub[newSrc].transforms) {
170 |
171 | newCid = unEscapeDot(cid);
172 | hub[newSrc].transforms[newCid] = hub[newSrc].transforms[cid];
173 | if (newCid !== cid) {
174 | delete hub[newSrc].transforms[cid];
175 | }
176 |
177 | }
178 | }
179 | }
180 |
181 | return hub;
182 | },
183 | },
184 | schedule: {
185 | type: Object,
186 | renderable: true,
187 | writable: true,
188 | default : {}
189 | },
190 | exports : { // user timezone
191 | type : Object,
192 | renderable : true,
193 | writable : true,
194 | get : function(val) {
195 | return val ? JSON.parse(val) : val;
196 | },
197 | set : function(val) {
198 | return val ? JSON.stringify(val) : val;
199 | }
200 | },
201 | search : {
202 | type : String,
203 | renderable : false,
204 | writable : false,
205 | },
206 | votes: {
207 | type: Number,
208 | renderable: true,
209 | writable: false,
210 | "default" : 0
211 | },
212 | installs: {
213 | type: Number,
214 | renderable: true,
215 | writable: false,
216 | "default" : 0
217 | },
218 | created : {
219 | type: Number,
220 | renderable: true,
221 | writable: false
222 | },
223 | updated : {
224 | type: Number,
225 | renderable: true,
226 | writable: false
227 | }
228 | };
229 |
230 | BipShare.links = function( accountInfo ) {
231 | var links = [];
232 |
233 | links.push({
234 | name : 'oembed',
235 | title : 'oEmbed',
236 | description : 'Retrieves The oEmbed For This Share',
237 | contentType : DEFS.CONTENTTYPE_JSON,
238 | _href : this._dao.getBaseUrl() + '/rpc/oembed/?url=' + this.href()
239 | });
240 |
241 | return links;
242 | }
243 |
244 | //
245 | BipShare.preSave = function(accountInfo, next) {
246 | // rebuild search terms
247 | var note = this.note || '',
248 | name = this.name || '',
249 | manifest = this.manifest ? this.manifest.join('" "') : '',
250 | searchStr = '',
251 | pod,
252 | tokens;
253 |
254 | searchStr += (note ? ('"' + note + '"') : '') + '"' + name + '" "' + manifest + '"';
255 |
256 | if (this.manifest) {
257 | for (var i = 0; i < this.manifest.length; i++) {
258 | tokens = this.manifest[i].split('.');
259 | pod = this._dao.pod(tokens[0]);
260 | if (pod) {
261 | searchStr += ' "' + pod.getAction(tokens[1]).title + '"';
262 | }
263 | }
264 | }
265 |
266 | this.search = searchStr;
267 |
268 | next(false, this);
269 | };
270 |
271 | BipShare.compoundKeyConstraints = {
272 | owner_id : 1,
273 | slug: 1
274 | };
275 |
276 | module.exports.BipShare = BipShare;
277 |
--------------------------------------------------------------------------------
/src/models/channel_log.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * Channel Activity + Error Log
24 | *
25 | */
26 | var ChannelLogModel = require('./prototype.js').BipModel,
27 | ChannelLog = Object.create(ChannelLogModel);
28 |
29 | ChannelLog.codes = {
30 | 'channel_create' : 'Created',
31 | 'channel_error' : 'Error'
32 | }
33 |
34 | ChannelLog.entityName = 'channel_log';
35 | ChannelLog.entitySchema = {
36 | id: { // log
37 | type: String,
38 | renderable: true,
39 | writable: false
40 | },
41 | owner_id : {
42 | type: String,
43 | renderable: false,
44 | index: true,
45 | writable: false
46 | },
47 | channel_id : {
48 | type: String,
49 | renderable: false,
50 | index: true,
51 | writable: false
52 | },
53 | transaction_id : {
54 | type: String,
55 | renderable: true,
56 | writable: false
57 | },
58 | code : {
59 | type: String,
60 | renderable: true,
61 | writable: false,
62 | set : function(code) {
63 | if (ChannelLog.codes[code]) {
64 | this.message = ChannelLog.codes[code];
65 | }
66 | return code;
67 | }
68 | },
69 | bip_id : { // transaction source
70 | type: String,
71 | renderable: true,
72 | writable: false
73 | },
74 | message : {
75 | type: String,
76 | renderable: true,
77 | writable: false
78 | },
79 | created : {
80 | type: Number,
81 | renderable: true,
82 | writable: false
83 | }
84 | };
85 |
86 | module.exports.ChannelLog = ChannelLog;
87 |
--------------------------------------------------------------------------------
/src/models/domain.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 | var BipModel = require('./prototype.js').BipModel,
21 | Domain = Object.create(BipModel),
22 | dns = require('dns'),
23 | step = require('../lib/step');
24 |
25 | Domain.uniqueKeys = ['name'];
26 | Domain.entityName = 'domain';
27 | Domain.entitySchema = {
28 | id: {
29 | type: String,
30 | index : true,
31 | renderable: true,
32 | writable: false
33 | },
34 | owner_id : {
35 | type: String,
36 | index : true,
37 | renderable: false,
38 | writable: false
39 | },
40 | type: {
41 | type: String,
42 | renderable: false,
43 | writable: false,
44 | "default" : "custom"
45 | },
46 | _available: {
47 | type: Boolean,
48 | renderable: true,
49 | writable: false,
50 | "default" : false
51 | },
52 | name: {
53 | type: String,
54 | renderable: true,
55 | index : true,
56 | writable: true,
57 | validate : [
58 | {
59 | validator : function(val, next) {
60 | if (process.env.NODE_ENV !== 'production') {
61 | next(true);
62 | return;
63 | }
64 |
65 | var ok = /[\w\d]+\.[a-zA-Z]{2,}$/.test(val);
66 | if (ok) {
67 |
68 | var isLocal = Domain.isLocal(val);
69 | if (this.type == 'custom') {
70 | ok = !isLocal;
71 | } else {
72 | // lock vanity domains as unwritable
73 | ok = (!isLocal && this.type != 'vanity');
74 | }
75 | }
76 | next(ok);
77 | },
78 | msg : "Can not overwrite a protected Domain"
79 | },
80 | ]
81 | },
82 | renderer : {
83 | type : Object,
84 | renderable : true,
85 | writable : true,
86 | validate : [
87 | {
88 | validator : function(val, next) {
89 | self._dao.validateRPC(
90 | val,
91 | this.getAccountInfo(),
92 | function(err, ok) {
93 | next(!err && ok);
94 | }
95 | );
96 | },
97 | msg : 'Renderer RPC Not Found'
98 | }
99 | ]
100 | }
101 | };
102 |
103 | // is a local domain
104 | Domain.isLocal = function(domain) {
105 | var local = GLOBAL.CFG.domain_public.split(':').shift().replace(/\./g, '\\.'),
106 | reg = new RegExp(local + '$');
107 | return reg.test(domain);
108 | }
109 |
110 | /**
111 | *
112 | *
113 | */
114 | Domain.setAvailable = function(available, next) {
115 | var self = this;
116 | self._available = available;
117 |
118 | if (self.id) {
119 | this._dao.updateColumn(
120 | 'domain',
121 | self.id,
122 | {
123 | '_available' : available
124 | },
125 | function(err, result) {
126 | if (err) {
127 | console.log(err);
128 | }
129 | next(err, 'domain', self, 200);
130 | }
131 | );
132 | } else {
133 | next(false, 'domain', self, 200);
134 | }
135 | };
136 |
137 | Domain.verify = function(accountInfo, next) {
138 | var self = this, dao = this._dao;
139 | if (/.?localhost$/.test(self.name)) {
140 | self.setAvailable(true, next);
141 | return;
142 | }
143 |
144 | step(
145 | function domainVerify() {
146 | dns.resolveMx(
147 | self.name,
148 | this.parallel()
149 | );
150 |
151 | dns.resolveCname(
152 | self.name,
153 | this.parallel()
154 | );
155 | },
156 | function collateResults(err, MXAddr, CNAMEAddr) {
157 | self._available = false;
158 | if (!MXAddr && !CNAMEAddr && null != err) {
159 | if (err.errno == 'ENOTFOUND' || err.errno == 'ENODATA') {
160 | next(err, 'domain', self, 202);
161 | } else {
162 | next(err, 'domain', self, 500);
163 | }
164 |
165 | } else {
166 |
167 | accountInfo.getDefaultDomain(function(err, domain) {
168 |
169 | var ok = false;
170 |
171 | if (MXAddr && MXAddr.length > 0) {
172 | for (var i = 0; i < MXAddr.length; i++) {
173 | if (MXAddr[i].exchange && MXAddr[i].exchange == domain.name) {
174 | ok = true;
175 | }
176 | }
177 | }
178 |
179 | if (CNAMEAddr && CNAMEAddr.length > 0) {
180 | if (app.helper.inArray(CNAMEAddr, domain.name)) {
181 | ok = true;
182 | }
183 | }
184 |
185 | if (ok) {
186 | self.setAvailable(true, next);
187 | } else {
188 | // accepted - domain exists but is not bound to local application
189 | next(err, 'domain', self, 202);
190 | }
191 |
192 | });
193 | }
194 |
195 | }
196 | );
197 | }
198 |
199 | // domains behave a little differently, they can have postponed availability
200 | // after creation as we verify the domain is properly configured
201 | Domain.postSave = function(accountInfo, next) {
202 | var self = this, dao = this._dao;
203 | if (!this.isLocal(this.name)) {
204 | this.verify(accountInfo, next);
205 | } else {
206 | next(false, 'domain', self, 200);
207 | }
208 | }
209 |
210 | Domain.repr = function(accountInfo, next) {
211 | return this.name;
212 | }
213 |
214 | Domain.entitySetters = {
215 | 'name' : function(name) {
216 | return name.toLowerCase();
217 |
218 | }
219 | };
220 |
221 | Domain.compoundKeyConstraints = {
222 | name : 1
223 | };
224 |
225 | module.exports.Domain = Domain;
226 |
--------------------------------------------------------------------------------
/src/models/migration.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 | var BipModel = require('./prototype.js').BipModel;
21 | var Migration = Object.create(BipModel);
22 |
23 | Migration.entityName = 'migration';
24 | Migration.entitySchema = {
25 | id: {
26 | type: String,
27 | renderable: false,
28 | writable: false
29 | },
30 | zone : {
31 | type : String,
32 | renderable : false,
33 | writable : false,
34 | "default" : "system"
35 | },
36 | version : {
37 | type: String,
38 | renderable: false,
39 | writable: false
40 | },
41 | versionInt : {
42 | type: Number,
43 | renderable: false,
44 | writable: false
45 | }
46 | };
47 |
48 | module.exports.Migration = Migration;
49 |
--------------------------------------------------------------------------------
/src/models/prototype.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * BipModel is our local representation of a persistent model
24 | *
25 | */
26 | var clone = require('clone'),
27 | lodash = require('lodash'),
28 | helper = require('../lib/helper');
29 |
30 | var BipModel = {
31 | entityIndex: 'id',
32 | entityExpiration: 60*5,
33 | entityCreated: 'created',
34 |
35 | entitySetters: {},
36 |
37 | _accountInfo : null,
38 |
39 | compoundKeyConstraints: undefined,
40 |
41 | // list of unique keys
42 | uniqueKeys: [],
43 |
44 | helper : helper,
45 | _dao : undefined,
46 |
47 | serverInfo : undefined,
48 |
49 | bindServerMeta: function(serverInfo) {
50 | this.serverInfo = serverInfo;
51 | },
52 |
53 | href: function() {
54 | return this._dao.getBaseUrl() + '/rest/' + this.entityName + '/' + this.getIdValue();
55 | },
56 |
57 | // static prototype constructor
58 | staticInit: function(dao) {
59 |
60 | this._dao = dao;
61 |
62 | this.staticChildInit();
63 | },
64 |
65 | // @todo create a proper inheritence chain
66 | staticChildInit : function() {
67 |
68 | },
69 |
70 | // instance constructor
71 | init: function(accountInfo) {
72 | this._accountInfo = accountInfo;
73 | return this;
74 | },
75 |
76 | renderablePropsArray : undefined,
77 | writablePropsArray : undefined,
78 |
79 | getDao: function() {
80 | return this._dao;
81 | },
82 |
83 | getAccountInfo: function() {
84 | return this._accountInfo;
85 | },
86 |
87 | getCompoundKeyConstraints: function() {
88 | return this.compoundKeyConstraints;
89 | },
90 |
91 | repr: function(accountInfo) {
92 | return '';
93 | },
94 |
95 | links : function() {
96 | return [];
97 | },
98 |
99 | setValue: function(key, value) {
100 | this.key = value;
101 | },
102 |
103 | /**
104 | * populates this object with src
105 | *
106 | * trusts tainted sources
107 | */
108 | populate: function(src, accountInfo) {
109 | // copy from source into this model, override
110 | lodash.assign(this, src);
111 | this.decorate(accountInfo);
112 | },
113 |
114 | /*
115 | * adds attribute decorators
116 | */
117 | decorate: function(accountInfo) {
118 | if (undefined != accountInfo && this.id) {
119 | this._repr = this.repr(accountInfo);
120 | this._links = this.links(accountInfo);
121 | }
122 |
123 | if (this.getEntityIndex() && this[this.getEntityIndex()]) {
124 | this._href = this.href();
125 | }
126 | },
127 |
128 | toObj : function() {
129 |
130 | var obj = {
131 | _repr : this._repr,
132 | _href : this._href,
133 | _links : this._links
134 | },
135 | self = this;
136 |
137 | _.each(this.entitySchema, function(value, key) {
138 | obj[key] = lodash.cloneDeep(self[key]);
139 | });
140 |
141 | return obj;
142 | },
143 |
144 | toMongoModel: function(mongoModel) {
145 | var model = helper.copyProperties(this, mongoModel, true);
146 | var self = this;
147 | model.getAccountInfo = function() {
148 | return self.getAccountInfo();
149 | }
150 |
151 | model.getDao = function() {
152 | return self.getDao();
153 | }
154 |
155 | return model;
156 | },
157 |
158 | // called after successfully saving the object
159 | postSave: function(accountInfo, cb) {
160 | cb(false, this.getEntityName(), this);
161 | },
162 |
163 | // called prior to save
164 | preSave: function(accountInfo, next) {
165 | next(false, this);
166 | },
167 |
168 | preRemove : function(id, accountInfo, cb) {
169 | cb(false, this.getEntityName(), this)
170 | },
171 |
172 | prePatch : function(patch, accountInfo, cb) {
173 | cb(false, this.getEntityName(), patch);
174 | },
175 |
176 | getIdValue: function() {
177 | return this.id;
178 | },
179 |
180 | getValue: function(prop) {
181 | return (this.hasOwnProperty(prop)) ? this[prop] : undefined;
182 | },
183 |
184 | setId: function(newId) {
185 | this.id = newId;
186 | },
187 |
188 | getEntityName: function() {
189 | return this.entityName
190 | },
191 |
192 | getEntityIndex: function() {
193 | return this.entityIndex;
194 | },
195 |
196 | getEntityExpiration: function() {
197 | return this.entityExpiration;
198 | },
199 |
200 | getEntityCreated: function() {
201 | return this.entityCreated;
202 | },
203 |
204 | getEntitySchema: function() {
205 | return this.entitySchema;
206 | },
207 |
208 | isReadable: function(attr) {
209 | var ok = false,
210 | schema = this.getEntitySchema();
211 |
212 | switch (attr) {
213 | case '_repr' :
214 | case '_href' :
215 | case '_links' :
216 | case 'status' :
217 | case 'message' :
218 | case 'code' :
219 | case 'errors' :
220 | ok = true;
221 | break;
222 |
223 | default :
224 | ok = schema[attr] && schema[attr].renderable;
225 | }
226 |
227 | return ok;
228 | },
229 |
230 | isWritable: function(attr) {
231 | var schema = this.getEntitySchema();
232 | return schema[attr] && schema[attr].writable;
233 | },
234 |
235 |
236 | getClass: function() {
237 | return this;
238 | },
239 |
240 | getValidators : function(attr) {
241 | var validators,
242 | schema = this.getEntitySchema();
243 |
244 | if (schema[attr] && schema[attr].validate) {
245 | validators = schema[attr].validate;
246 | }
247 | return validators;
248 | },
249 |
250 | testProperty : function(prop) {
251 | return this.getEntitySchema().hasOwnProperty(prop);
252 | }
253 | }
254 |
255 | BipModel.validators = {
256 | 'notempty' : function(val, next) {
257 | next(undefined != val && val != '' && null != val);
258 | },
259 | 'len_64' : function(val, next) {
260 | next(!val || val.length <= 64);
261 | },
262 | 'len_32' : function(val, next) {
263 | next(!val || val.length <= 32);
264 | },
265 | 'max_32' : function(val, next) {
266 | next(!val || val.length <= 32);
267 | },
268 | 'max_64' : function(val, next) {
269 | next(!val || val.length <= 64);
270 | },
271 | 'max_text' : function(val, next) {
272 | next(!val || val.length <= 1024);
273 | },
274 | 'bool_int' : function(val, next) {
275 | next(val == 0 || val == 1);
276 | },
277 | 'bool_any' : function(val, next) {
278 | var bools = [
279 | 1,
280 | 0,
281 | '1',
282 | '0',
283 | true,
284 | false,
285 | 'true',
286 | 'false'
287 | ];
288 | next(-1 !== bools.indexOf(val));
289 | },
290 | //
291 | 'accountModelDomain' : function(val, next) {
292 | var filter = {
293 | id : this.domain_id,
294 | owner_id : this.owner_id
295 | };
296 |
297 | this.getDao().find('domain', filter, function(err, result) {
298 | next(!err);
299 | });
300 | },
301 | // validates email format and whether the domian looks to be valid
302 | 'email' : function(val, next) {
303 | var validFormat = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i.test(val);
304 | var domainTokens = tldtools.extract('mailto:' + val);
305 | next(validFormat && domainTokens.inspect.useful() );
306 | }
307 | }
308 |
309 | module.exports.BipModel = BipModel;
310 |
--------------------------------------------------------------------------------
/src/models/stats_account.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 | var StatsAccountModel = require('./prototype.js').BipModel,
21 | StatsAccount = Object.create(StatsAccountModel);
22 |
23 | StatsAccount.entityName = 'stats_account';
24 | StatsAccount.entitySchema = {
25 | id: {
26 | type: String,
27 | renderable: false,
28 | writable: false
29 | },
30 | day: { // day
31 | type: String,
32 | renderable: false,
33 | writable: false
34 | },
35 | owner_id : {
36 | type: String,
37 | renderable: false,
38 | writable: false
39 | },
40 | bips_total: {
41 | type: Number,
42 | renderable: true,
43 | writable: true,
44 | "default" : 0
45 | },
46 | share_total: {
47 | type: Number,
48 | renderable: true,
49 | writable: true,
50 | "default" : 0
51 | },
52 | channels_total: {
53 | type: Number,
54 | renderable: true,
55 | writable: true,
56 | "default" : 0
57 | },
58 | delivered_bip_inbound: {
59 | type: Number,
60 | renderable: true,
61 | writable: true,
62 | "default" : 0
63 | },
64 | delivered_channel_outbound : {
65 | type: Number,
66 | renderable: true,
67 | writable: true,
68 | "default" : 0
69 | },
70 | traffic_inbound_mb: {
71 | type: Number,
72 | renderable: true,
73 | writable: true,
74 | "default" : 0
75 | },
76 | traffic_outbound_mb: {
77 | type: Number,
78 | renderable: true,
79 | writable: true,
80 | "default" : 0
81 | }
82 | };
83 |
84 | StatsAccount.compoundKeyConstraints = {
85 | owner_id : 1,
86 | day : 1,
87 | id : 1
88 | };
89 |
90 | module.exports.StatsAccount = StatsAccount;
91 |
--------------------------------------------------------------------------------
/src/models/stats_account_network.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 | var StatsAccountNetworkNetworkModel = require('./prototype.js').BipModel,
21 | StatsAccountNetwork = Object.create(StatsAccountNetworkNetworkModel);
22 |
23 | StatsAccountNetwork.entityName = 'stats_account_network';
24 | StatsAccountNetwork.entitySchema = {
25 | id: {
26 | type: String,
27 | renderable: false,
28 | writable: false
29 | },
30 | day: { // day
31 | type: Number,
32 | renderable: true,
33 | writable: false
34 | },
35 | owner_id : {
36 | type: String,
37 | renderable: false,
38 | writable: false
39 | },
40 | data: {
41 | type: Object,
42 | renderable: true,
43 | writable: false
44 | },
45 | updated_at: {
46 | type: Number,
47 | renderable: false,
48 | writable: false
49 | }
50 | };
51 |
52 | StatsAccountNetwork.compoundKeyConstraints = {
53 | owner_id : 1,
54 | day : 1
55 | };
56 |
57 | module.exports.StatsAccountNetwork = StatsAccountNetwork;
58 |
--------------------------------------------------------------------------------
/src/models/stats_global.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | *
20 |
21 | */
22 | /**
23 | *
24 | * Provides general system statistics, by day
25 | *
26 | */
27 | var StatsGlobalModel = require('./prototype.js').BipModel,
28 | StatsGlobal = Object.create(StatsGlobalModel);
29 |
30 | StatsGlobal.entityName = 'stats_account';
31 | StatsGlobal.entitySchema = {
32 | id: { // day
33 | type: String,
34 | renderable: true,
35 | writable: false
36 | },
37 | users_new : {
38 | type: String,
39 | renderable: true,
40 | writable: true
41 | },
42 | users_signin : {
43 | type: String,
44 | renderable: true,
45 | writable: true
46 | },
47 |
48 | // by bip type
49 | new_bip_breakdown : {
50 | type : Object,
51 | renderable: true,
52 | writable: true
53 | },
54 | new_bips_total: {
55 | type: Integer,
56 | renderable: true,
57 | writable: true
58 | },
59 |
60 | // by channel action
61 | new_channel_breakdown : {
62 | type : Object,
63 | renderable: true,
64 | writable: true
65 | },
66 | new_channels_total: {
67 | type: Integer,
68 | renderable: true,
69 | writable: true
70 | },
71 |
72 | channels_unverified: {
73 | type: Integer,
74 | renderable: true,
75 | writable: true
76 | },
77 |
78 |
79 | new_domains_total: {
80 | type: Integer,
81 | renderable: true,
82 | writable: true
83 | },
84 |
85 | delivered_bip_inbound: {
86 | type: Integer,
87 | renderable: true,
88 | writable: true
89 | },
90 | delivered_channel_outbound : {
91 | type: Array,
92 | renderable: true,
93 | writable: true
94 | },
95 |
96 | traffic_inbound: {
97 | type: Integer,
98 | renderable: true,
99 | writable: true
100 | },
101 | traffic_outbound: {
102 | type: Integer,
103 | renderable: true,
104 | writable: true
105 | },
106 |
107 | demographic_users_male: {
108 | type: Integer,
109 | renderable: true,
110 | writable: true
111 | },
112 |
113 | demographic_users_female: {
114 | type: Integer,
115 | renderable: true,
116 | writable: true
117 | },
118 |
119 | demographic_users_unknown: {
120 | type: Integer,
121 | renderable: true,
122 | writable: true
123 | }
124 | };
125 |
126 | module.exports.StatsGlobal = StatsGlobal;
--------------------------------------------------------------------------------
/src/models/transform_default.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * The Bipio API Server
4 | *
5 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | */
20 |
21 | /**
22 | *
23 | * TranslateDefault is responsible for surfacing transforms between two channels
24 | * based on the last saved transform for the channels by the client, or otherwise
25 | * from the system.
26 | *
27 | */
28 | var BipModel = require('./prototype.js').BipModel,
29 | TransformDefault = Object.create(BipModel);
30 |
31 | TransformDefault.compoundKeyConstraints = {
32 | owner_id : 1,
33 | from_channel : 1,
34 | to_channel : 1
35 | };
36 | TransformDefault.entityName = 'transform_default';
37 | TransformDefault.entitySchema = {
38 | id: {
39 | type: String,
40 | index: true,
41 | renderable: false,
42 | writable: false
43 | },
44 | owner_id : { // owner_id 'system' = system determined map
45 | type: String,
46 | index: true,
47 | renderable: false,
48 | writable: false
49 | },
50 | from_channel: { // channel action (pod.action)
51 | type: String,
52 | index: true,
53 | renderable: true,
54 | writable: false
55 | },
56 | to_channel: { // channel action (pod.action)
57 | type: String,
58 | index: true,
59 | renderable: true,
60 | writable: false
61 | },
62 | transform : { // serialized transform
63 | type: Object,
64 | renderable: true,
65 | writable: false
66 | },
67 | created : {
68 | type: Number,
69 | renderable: true,
70 | writable: false
71 | }
72 | };
73 |
74 | module.exports.TransformDefault = TransformDefault;
75 |
--------------------------------------------------------------------------------
/src/modules/auth/http_basic.js:
--------------------------------------------------------------------------------
1 |
2 | var proto = require('./native');
3 |
4 | function HTTPBasic(options) {
5 | this.options = options;
6 | }
7 |
8 | HTTPBasic.prototype = proto.prototype;
9 |
10 | /*
11 | * Remote HTTP Basic Auth
12 | */
13 | HTTPBasic.prototype.test = function(username, password, opts, next) {
14 | var self = this,
15 | dao = this.dao,
16 | filter = {},
17 | options = this.options;
18 |
19 | if ('admin' === username || opts.asOwner) {
20 | this.__proto__._test.apply(this, arguments);
21 |
22 | } else if (!username || !password) {
23 | next(self.MSG_NOT_AUTHORIZED, null);
24 |
25 | } else {
26 |
27 | this.__proto__._test.call(this, username, password, opts, function(err, result) {
28 | if (err) {
29 | // try to auth and sync off ldap auth service
30 | request.get(
31 | {
32 | "url" : options.url,
33 | "auth" : {
34 | "user" : username,
35 | "pass" : password,
36 | "sendImmediately" : true
37 | }
38 | },
39 | function(err, res, body) {
40 | if (err) {
41 | next(err);
42 | } else if (200 !== res.statusCode) {
43 | next('Not Authorized');
44 | } else {
45 | dao.find(
46 | 'account',
47 | {
48 | username : username
49 | },
50 | function(err, acctResult) {
51 | if (!err && (null != acctResult)) {
52 |
53 | var filter = {
54 | 'owner_id' : acctResult.id,
55 | 'type' : 'token'
56 | }
57 |
58 | dao.find('account_auth', filter, function(isErr, authResult) {
59 | var resultModel = null;
60 | if (!isErr && null != authResult) {
61 |
62 | self.acctBind(acctResult, authResult, options, function(err, accountInfo) {
63 | if (err) {
64 | next(err);
65 | } else {
66 | try {
67 | accountInfo._remoteBody = JSON.parse(body);
68 | } catch (e) {
69 | accountInfo._remoteBody = body;
70 | }
71 | next(false, accountInfo);
72 | }
73 | });
74 |
75 | } else {
76 | next(self.MSG_NOT_AUTHORIZED, resultModel);
77 | }
78 | });
79 |
80 | // if user auths off and option set, auto create
81 | // local account
82 | } else if (!acctResult && options.auto_sync && options.auto_sync.mail_field) {
83 | var emailAddress;
84 |
85 | // if no email address found, create a local dummy
86 | if ('none' === options.auto_sync.mail_field) {
87 | emailAddress = 'noreply@' + username + '.' + CFG.domain;
88 | } else {
89 | emailAddress = app.helper.jsonPath(body, options.auto_sync.mail_field);
90 | }
91 |
92 | if (emailAddress) {
93 |
94 | dao.createUser(username, emailAddress, null, function(err, authResult) {
95 |
96 | authResult.username = username;
97 | authResult.name = username
98 | authResult.account_level = GLOBAL.DEFS.ACCOUNT_LEVEL.USER;
99 |
100 | self.acctBind(authResult, authResult, options, function(err, accountInfo) {
101 | if (err) {
102 | next(err);
103 |
104 | } else {
105 | try {
106 | accountInfo._remoteBody = JSON.parse(body);
107 | } catch (e) {
108 | accountInfo._remoteBody = body;
109 | }
110 | next(false, accountInfo);
111 | }
112 | });
113 |
114 | });
115 |
116 | } else {
117 | next(self.MSG_NOT_AUTHORIZED, null);
118 | }
119 | } else {
120 | app.logmessage('No Email field found to sync for ' + username + ', skipping auth', 'error');
121 | next(self.MSG_NOT_AUTHORIZED, null);
122 | }
123 | }
124 | );
125 | }
126 | }
127 | );
128 | } else {
129 | next(err, result);
130 | }
131 | });
132 |
133 | }
134 | }
135 |
136 | module.exports = HTTPBasic;
--------------------------------------------------------------------------------
/src/modules/auth/ldap.js:
--------------------------------------------------------------------------------
1 |
2 | var proto = require('./native'),
3 | ldap = require('ldapjs');
4 |
5 | function LDAP(options) {
6 | this.options = options;
7 |
8 | this._ldapClient = ldap.createClient(options.server);
9 | }
10 |
11 | LDAP.prototype = proto.prototype;
12 |
13 | /*
14 | * Remote HTTP Basic Auth
15 | */
16 | LDAP.prototype.test = function(username, password, opts, next) {
17 | var self = this,
18 | dao = this.dao,
19 | filter = {},
20 | options = this.options;
21 |
22 | if ('admin' === username || opts.asOwner) {
23 | this.__proto__._test.apply(this, arguments);
24 |
25 | } else if (!username || !password) {
26 | next(self.MSG_NOT_AUTHORIZED, null);
27 |
28 | } else {
29 |
30 | var client = this._ldapClient,
31 | base = options.base,
32 | search = app._.clone(options.search),
33 | bind = true;
34 |
35 | if (search.filter) {
36 | search.filter = search.filter.replace(/{{username}}/, username);
37 | }
38 |
39 | client.search(base, search, function(err, res) {
40 | if (err) {
41 | next(err);
42 | } else {
43 |
44 | var foundMatch = false,
45 | notFoundMsg = 'Not Found';
46 |
47 | res.on('end', function() {
48 | if (!foundMatch) {
49 | next(notFoundMsg, null);
50 | }
51 | });
52 |
53 | res.on('searchEntry', function(entry) {
54 | foundMatch = true;
55 |
56 | client.compare(entry.dn, 'userPassword', password, function(err, pass ) {
57 |
58 | if (err) {
59 | next(err);
60 |
61 | } else if (!pass) {
62 | next('Not Authorized')
63 |
64 | } else {
65 |
66 | // auth continue
67 | dao.find(
68 | 'account',
69 | {
70 | username : username
71 | },
72 | function(err, acctResult) {
73 | if (!err && (null != acctResult)) {
74 |
75 | var filter = {
76 | 'owner_id' : acctResult.id,
77 | 'type' : 'token'
78 | }
79 |
80 | dao.find('account_auth', filter, function(isErr, authResult) {
81 | var resultModel = null;
82 | if (!isErr && null != authResult) {
83 |
84 | self.acctBind(acctResult, authResult, options, function(err, accountInfo) {
85 | next(false, accountInfo);
86 | });
87 |
88 | } else {
89 | next(self.MSG_NOT_AUTHORIZED, resultModel);
90 | }
91 | });
92 |
93 | // if user auths off and option set, auto create
94 | // local account
95 | } else if (!acctResult && options.auto_sync && options.auto_sync.mail_field) {
96 | var emailAddress;
97 |
98 | // if no email address found, create a local dummy
99 | if ('none' === options.auto_sync.mail_field) {
100 | emailAddress = 'noreply@' + username + '.' + CFG.domain;
101 | } else {
102 | for (var i = 0; i < entry.attributes.length; i++) {
103 | if (options.auto_sync.mail_field === entry.attributes[i].type) {
104 | emailAddress = entry.attributes[i].vals.pop();
105 | break;
106 | }
107 | }
108 | }
109 |
110 | if (emailAddress) {
111 |
112 | dao.createUser(username, emailAddress, null, function(err, authResult) {
113 | authResult.username = username;
114 | authResult.name = username
115 | authResult.account_level = GLOBAL.DEFS.ACCOUNT_LEVEL.USER;
116 |
117 | self.acctBind(authResult, authResult, options, function(err, accountInfo) {
118 | next(false, accountInfo);
119 | });
120 |
121 | });
122 |
123 | } else {
124 | next(self.MSG_NOT_AUTHORIZED, null);
125 | }
126 | } else {
127 | app.logmessage('No Email field found to sync for ' + username + ', skipping auth', 'error');
128 | next(self.MSG_NOT_AUTHORIZED, null);
129 | }
130 | }
131 | );
132 | }
133 | });
134 | });
135 | }
136 | });
137 | }
138 | }
139 |
140 | module.exports = LDAP;
--------------------------------------------------------------------------------
/src/modules/auth/models/account_info.js:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | *
4 | */
5 | function AccountInfo(account, dao) {
6 | this.user = account;
7 | this.dao = dao;
8 |
9 | this.collections = {};
10 | this.activeDomain = null;
11 | }
12 |
13 | AccountInfo.prototype = {
14 |
15 | _load : function(collection, next) {
16 | var self = this;
17 |
18 | if (!this.collections[collection]) {
19 | this.dao.findFilter(
20 | collection,
21 | {
22 | owner_id : this.user.id
23 | },
24 | function(err, result) {
25 | self.collections[collection] = result;
26 | if (next) {
27 | next(err, result);
28 | }
29 |
30 | return self.collections[collection];
31 | }
32 | );
33 | } else {
34 |
35 | if (next) {
36 | next(false, this.collections[collection]);
37 | }
38 |
39 | return this.collections[collection];
40 | }
41 | },
42 |
43 | getSettings : function(next) {
44 | var self = this;
45 | return this._load('account_option', function(err, settings) {
46 |
47 | if (app.helper.isArray(settings)) {
48 | self.settings = settings[0];
49 |
50 | } else {
51 | self.settings = settings;
52 | }
53 |
54 | next(err, self.settings.toJSON ? self.settings.toJSON() : self.settings);
55 | });
56 | },
57 |
58 | getSetting : function(name, next) {
59 | this.getSettings(function(err, settings) {
60 | next(err, settings[name]);
61 | });
62 | },
63 |
64 | getDomains : function(next) {
65 | return this._load('domain', next);
66 | },
67 |
68 | getDomain : function(domainId, next) {
69 | this.getDomains(function(err, domains) {
70 | next(err, _.where(domains, { id : domainId }) );
71 | });
72 | },
73 |
74 | testDomain : function(domainId, next) {
75 | this.getDomains(function(err, domains) {
76 | next(err, !!_.where(domains, { id : domainId}).length );
77 | });
78 | },
79 |
80 | getChannels : function(next) {
81 | this._load('channel', next);
82 | },
83 |
84 | getChannel : function(cid, next) {
85 | this.getChannels(function(err, channels) {
86 | next(err, _.findWhere(channels, { id : cid}) );
87 | });
88 | },
89 |
90 | testChannel : function(cid, next) {
91 | this.getChannels(function(err, channels) {
92 | next(err, !!_.where(channels, { id : cid}).length );
93 | });
94 | },
95 |
96 | getId : function() {
97 | return this.user.id;
98 | },
99 |
100 | getName : function() {
101 | return this.user.name;
102 | },
103 |
104 | getUserName : function() {
105 | return this.user.username;
106 | },
107 |
108 | getActiveDomain : function() {
109 | return this.activeDomain;
110 | },
111 |
112 | getDefaultDomain: function(next) {
113 | this.getDomains(
114 | function(err, domains) {
115 | next(err, _.findWhere(domains, { type : 'vanity'} ) );
116 | }
117 | );
118 | },
119 |
120 | getDefaultDomainStr : function(next) {
121 | this.getDefaultDomain(function(err, domain) {
122 | next(err, CFG.proto_public + domain.name)
123 | });
124 | },
125 |
126 | setActiveDomain : function(domainId, next) {
127 | var self = this;
128 | if (domainId) {
129 | this.getDomains(function(err, domains) {
130 | self.activeDomain = _.findWhere(domains, { id : domainId } );
131 | next();
132 | });
133 | } else {
134 | this.getDefaultDomain(function(err, domain) {
135 | self.activeDomain = domain;
136 | next();
137 | });
138 | }
139 | },
140 |
141 | getTimezone : function(next) {
142 | this.getSetting('timezone', next);
143 | }
144 | };
145 |
146 | module.exports = AccountInfo;
--------------------------------------------------------------------------------
/src/modules/auth/native.js:
--------------------------------------------------------------------------------
1 | var AccountInfo = require('./models/account_info.js');
2 |
3 | const MSG_NOT_AUTHORIZED = 'Not Authorized';
4 |
5 | /*
6 | * Account Authorization Module prototype
7 | *
8 | */
9 | function AuthModule(options) {
10 | this.options = options;
11 | }
12 |
13 | AuthModule.prototype = {
14 | MSG_NOT_AUTHORIZED : MSG_NOT_AUTHORIZED,
15 | setDAO : function(dao) {
16 | this.dao = dao;
17 | }
18 | };
19 |
20 | AuthModule.prototype.getAccountStruct = function(authModel, next) {
21 | // session usable abstract model of the account
22 | var account = new AccountInfo({
23 | id : authModel.owner_id,
24 | name : authModel.name,
25 | username : authModel.username,
26 | account_level: authModel.account_level,
27 | plan_until : authModel.plan_until,
28 | settings: {
29 | api_token: null
30 | }
31 | }, this.dao);
32 |
33 | // always load domain records for the account
34 | account.getDomains(function() {
35 | next(false, account);
36 | });
37 |
38 | }
39 |
40 | AuthModule.prototype.accountFactory = function(props) {
41 | return new AccountInfo(props);
42 | }
43 |
44 | /**
45 | *
46 | * Creates an AccountStruct from a username
47 | */
48 | AuthModule.prototype.getAccountStructByUsername = function(username, next) {
49 | var self = this;
50 |
51 | this.dao.find('account', { username : username }, function(err, result) {
52 | if (err || !result) {
53 | next(err ? err : "Not Found");
54 | } else {
55 | result.owner_id = result.id;
56 | self.getAccountStruct(result, next);
57 | }
58 | });
59 | }
60 |
61 | AuthModule.prototype.getAccountStructById = function(id, next) {
62 | var self = this;
63 |
64 | this.dao.find('account', { id : id }, function(err, result) {
65 | if (err || !result) {
66 | next(err ? err : "Not Found");
67 | } else {
68 | result.owner_id = result.id;
69 | self.getAccountStruct(result, next);
70 | }
71 | });
72 | }
73 |
74 | AuthModule.prototype.acctBind = function(account, accountAuth, options, next) {
75 | var masquerade = options.masquerade,
76 | activeDomainId = options.domainId,
77 | authModel = this.dao.modelFactory('account_auth', accountAuth);
78 |
79 | if (masquerade && 'admin' === account.account_level) {
80 | this.getAccountStructByUsername(masquerade, next);
81 |
82 | } else {
83 | accountAuth.username = account.username;
84 | accountAuth.name = account.name;
85 |
86 | // this should be injectable by the permissions module somehow
87 | accountAuth.account_level = account.account_level;
88 | accountAuth.plan_until = account.get('plan_until');
89 |
90 | this.getAccountStruct(accountAuth, function(err, accountInfo) {
91 |
92 | accountInfo.user.username = account.username;
93 |
94 | accountInfo.setActiveDomain(activeDomainId, function() {
95 | next(false, accountInfo);
96 | });
97 |
98 | });
99 | }
100 | }
101 |
102 | // --------- PUBLIC INTERFACES
103 |
104 | /**
105 | *
106 | * Tests authorization
107 | *
108 | * @param string username
109 | * @param string password
110 | * @param string type ()
111 | */
112 | AuthModule.prototype._test = function(username, password, options, next) {
113 | var dao = this.dao,
114 | self = this,
115 | filter = {};
116 |
117 | if (options.asOwner) {
118 | filter.id = username;
119 | } else {
120 | filter.username = username;
121 | }
122 |
123 | dao.find(
124 | 'account',
125 | filter,
126 | function(err, acctResult) {
127 | if (!err && (null != acctResult)) {
128 | var filter = {
129 | 'owner_id' : acctResult.id,
130 | 'type' : 'token'
131 | }
132 |
133 | dao.find('account_auth', filter, function(isErr, authResult) {
134 |
135 | var resultModel = null;
136 | if (!isErr && null != authResult) {
137 | var authModel = dao.modelFactory('account_auth', authResult);
138 | if (options.acctBind || authModel.cmpPassword(password)) {
139 | self.acctBind(acctResult, authResult, options, next);
140 |
141 | } else {
142 | next(MSG_NOT_AUTHORIZED);
143 | }
144 | } else {
145 | next(MSG_NOT_AUTHORIZED);
146 | }
147 | });
148 | } else {
149 | next(MSG_NOT_AUTHORIZED);
150 | }
151 | }
152 | );
153 | }
154 |
155 | AuthModule.prototype.test = function(username, password, options, next) {
156 | this.__proto__._test.apply(this, arguments);
157 | }
158 |
159 |
160 | /**
161 | * Creates AccountInfo context for a domain
162 | *
163 | * @param string domain domain name
164 | * @param function next callback(error, accountResult)
165 | */
166 | AuthModule.prototype.domainAuth = function(domainName, next) {
167 | var self = this;
168 |
169 | this.dao.find('domain', {
170 | 'name' : domainName
171 | }, function(err, domain) {
172 | if (err) {
173 | next(err);
174 | } else {
175 | if (domain) {
176 | self._test(
177 | domain.owner_id,
178 | '',
179 | {
180 | asOwner : true,
181 | acctBind : true,
182 | domainId : domain.id
183 | },
184 | function(err, accountInfo) {
185 | accountInfo.activeDomain = domain;
186 |
187 | next(err, accountInfo);
188 | }
189 | );
190 | } else {
191 | next('Not Found');
192 | }
193 | }
194 | });
195 | }
196 |
197 | module.exports = AuthModule;
198 |
--------------------------------------------------------------------------------
/src/modules/cdn/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/src/modules/cdn/README.md:
--------------------------------------------------------------------------------
1 | fs-cdn
2 | ======
3 |
4 | A streaming adapter between fs and pkgcloud
5 |
6 | fs-cdn allows you to mirror basic native `fs` and `pkgcloud` functionality. It abstracts the interface into an intuitive set of methods for basic file operations on either your local filesystem and a storage provider supported by `pkgcloud`.
7 |
8 | Getting Started
9 | ---------------
10 |
11 | There are two ways to install fs-cdn.
12 |
13 | npm install fs-cdn
14 |
15 | or
16 |
17 | git clone git@github.com:wotio/fs-cdn.git
18 | cd fs-cdn
19 | npm install
20 |
21 | Next, create a file called `config.json` in your project. It should have a structure that conforms to the pkgcloud config object, which varies per provider. Below is an example of a config using Rackspace Cloudfiles:
22 |
23 | {
24 | "data_dir" : "/path/to/data/dir" // required - the relative root directory, all paths will be relative to this
25 | "provider" : "rackspace",
26 | "username" : "", // provider-specific, see pkgcloud's storage docs for supported providers and their respective config requirements
27 | "apiKey" : "", // provider-specific
28 | "region" : "", // optional
29 | "container" : "" // optional, but without it you must specify the container per file operation
30 | }
31 |
32 | A sample script using `fs-cdn` would thus look something like this:
33 |
34 | ```Javascript
35 | var Fs_Cdn = require('fs-cdn'),
36 | remoteConfig = require(''),
37 | localConfig = require('');
38 |
39 | var fs_cdn_remote = new Fs_Cdn(remoteConfig),
40 | fs_cdn_local = new Fs_Cdn(localConfig);
41 | ```
42 |
43 | Available Methods
44 | -----------------
45 |
46 | ### **save(*dest*, *source*, *options*, *callback*)**
47 | Pipes ReadStream *source* to *dest*. If a string filepath is passed instead of a ReadStream, `save` creates a ReadStream from it.
48 |
49 | ***dest***: {string} Full path of destination file
50 | ***source***: {object or string} ReadStream or full path of source file
51 | ***options***: {object} Options object
52 | ***callback***: {function} Callback
53 |
54 | ```Javascript
55 | var options = {
56 | persist: @boolean, // If true, stores file in /perm subfolder. If false, stores files in /tmp
57 | append: @boolean, // If true, appends the source to the dest file, instead of overwriting
58 | compress: @boolean, // If true, compresses the file using gzip.
59 | write: @boolean // If true, looks for an instance of Buffer as argument[1] and writes it to the file.
60 | }
61 |
62 | fs_cdn_local.save('path/to/dest/filename.txt', <'path/to/src/filename.txt' or fs.createReadStream('path/to/src/filename.txt')>, options, function(err, result) {
63 |
64 | // result will be a file object like this:
65 | // {
66 | // size : @int,
67 | // localpath : @string,
68 | // name : @string,
69 | // type : @string,
70 | // encoding : 'binary'
71 | // }
72 |
73 | });
74 |
75 | fs_cdn_remote.save('path/to/dest/filename.txt', <'path/to/src/filename.txt' or fs.createReadStream('path/to/src/filename.txt')>, options, function(err, result) {
76 |
77 | // result will be a file object like this:
78 | // {
79 | // size : @int,
80 | // localpath : @string,
81 | // name : @string,
82 | // type : @string,
83 | // container: @string,
84 | // encoding : 'binary'
85 | // }
86 |
87 | });
88 | ```
89 |
90 | ### **get(*source*, *callback*)**
91 | Gets *source* and a readStream pointing to it. If a string filepath is passed instead of a File object, `get` normalizes it into a File object (after checking for its existence).
92 |
93 | ***source***: {object or string} Full path of source file or File object
94 | ***callback***: {function} Callback
95 |
96 | ```Javascript
97 | fs_cdn_local.get(<'path/to/src/filename.txt' or { localpath : 'path/to/src/filename.txt', name: 'filename.txt', encoding: 'binary' }>, function(err, result, readStream) {
98 |
99 | // result will be a file object like this:
100 | // {
101 | // size : @int,
102 | // localpath : @string,
103 | // name : @string,
104 | // type : @string,
105 | // container: @string,
106 | // encoding : 'binary'
107 | // }
108 | //
109 | // readStream will be an instance of fs.readStream from the filesystem
110 |
111 | });
112 |
113 | fs_cdn_remote.get(<'path/to/src/filename.txt' or { localpath : 'path/to/src/filename.txt', name: 'filename.txt', encoding: 'binary' }>, function(err, result, readStream) {
114 |
115 | // result will be a file object like this:
116 | // {
117 | // size : @int,
118 | // localpath : @string,
119 | // name : @string,
120 | // type : @string,
121 | // container: @string,
122 | // encoding : 'binary'
123 | // }
124 | //
125 | // readStream will be an instance of fs.readStream from the CDN storage provider
126 |
127 | });
128 | ```
129 |
130 | ### **list(*dir*, *callback*)** ->
131 | Lists all files in *dir* or in remote container
132 |
133 | ***dir***: {string} directory path (local) or container name (remote, optional if container was specified in config)
134 | ***callback***: {function} Callback
135 |
136 | ```Javascript
137 | fs_cdn_local.list('path/to/dst/dir', function(err, result) {
138 | // handle results
139 | });
140 | ```
141 |
142 | ```Javascript
143 | fs_cdn_remote.list(function(err, result) {
144 | // handle results
145 | });
146 | ```
147 |
148 | In the callback, `result` will be an array of the files in the container or folder.
149 |
150 | ### **find(*file*, *callback*)** ->
151 | Finds the specified file.
152 |
153 | ***file***: {string} directory path (local) or file name (remote)
154 | ***callback***: {function} Callback
155 |
156 | ```Javascript
157 | fs_cdn_local.find('path/to/local/filename.txt', function(err, result) {
158 | // handle results
159 | });
160 | ```
161 |
162 | In the callback, `results` object will be an instance of [fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats)
163 |
164 | ```Javascript
165 | fs_cdn_remote.find('filename.txt', function(err, result) {
166 | // handle results
167 | });
168 | ```
169 |
170 | In the callback, `result` object will be a pkgcloud [File Model](https://github.com/pkgcloud/pkgcloud/blob/master/docs/providers/rackspace/storage.md#file-model).
171 |
172 | ### **remove(*file*, *callback*)** ->
173 | Removes the specified file.
174 |
175 | ***file***: {string} directory path (local) or file name (remote)
176 | ***options***: {object} Options object
177 | ***callback***: {function} Callback
178 |
179 | ```Javascript
180 | fs_cdn_local.remove('path/to/local/filename.txt', function(err, result) {
181 | // handle results
182 | });
183 | ```
184 |
185 | ```Javascript
186 | fs_cdn_remote.remove('filename.txt', function(err, result) {
187 | // handle results
188 | });
189 | ```
--------------------------------------------------------------------------------
/src/modules/cdn/cdn.js:
--------------------------------------------------------------------------------
1 |
2 | var client = null,
3 | fs = require('fs'),
4 | FsProto = require('./fs.js'),
5 | pkgcloud = require('pkgcloud'),
6 | util = require('util');
7 |
8 | function CDNProto(options) {
9 | if (options.hasOwnProperty("provider")) {
10 | client = pkgcloud.storage.createClient(options);
11 | this.opts = options;
12 | }
13 | else {
14 | console.warn("Credentials not found. Initializing in local fs mode...")
15 | }
16 | };
17 |
18 | util.inherits(CDNProto, FsProto);
19 |
20 | CDNProto.prototype = {
21 |
22 | /*
23 | * Saves a file from a string or readStream, syncs to CDN, and returns file object
24 | *
25 | * dest: string or object
26 | * source: string or readStream
27 | * options: object [optional]
28 | * next: function(string err, object file)
29 | */
30 |
31 | save: function() {
32 | var self = this,
33 | dest = arguments[0],
34 | source = arguments[1],
35 | options = (arguments[2] ? arguments[2] : null),
36 | destPath = ((typeof dest === 'object') ? dest.localpath : dest),
37 | next = arguments[arguments.length-1],
38 | clientOpts = {
39 | container: ((options && options.container) ? options.container : self.opts.container),
40 | remote: destPath
41 | },
42 | readStream = ((typeof source === 'string') ? fs.createReadStream(source) : source),
43 | writeStream = client.upload(clientOpts),
44 | local = new FsProto({data_dir: this.opts.data_dir});
45 |
46 | local.save(dest, source, options, function(err, file) {
47 | if (err) next(err);
48 |
49 | writeStream.on('error', next);
50 | writeStream.on('success', function() {
51 | file.container = clientOpts.container;
52 | next(null, file);
53 | })
54 | });
55 |
56 | readStream.pipe(writeStream);
57 | },
58 |
59 | /*
60 | * Gets a file from a fileStruct, if id doesn't exist, check the CDN and return a new fileStruct and readStream from CDN
61 | *
62 | * source: string or object
63 | * next: function(string err, object file, readStream)
64 | */
65 |
66 | get: function() {
67 | var self = this,
68 | source = arguments[0],
69 | next = arguments[arguments.length-1],
70 | srcPath = ((typeof source === 'object') ? source.localpath : source),
71 | clientOpts = {
72 | container: (source.container ? source.container : self.opts.container),
73 | remote: srcPath
74 | },
75 | local = new FsProto({data_dir: this.opts.data_dir});
76 |
77 | if (typeof srcPath !== 'string') next("fs_cdn.get() requires either a valid path string or a File object with property 'localpath'.");
78 |
79 | fs.stat(srcPath, function(err, result) {
80 | if (err) {
81 | var readStream = client.download(clientOpts)
82 | local.save(srcPath, readStream, function(err, file) {
83 | if (err) next(err);
84 | file.container = clientOpts.container;
85 | next(null, result, readStream);
86 | });
87 | }
88 | else {
89 | readStream = fs.createReadStream(srcPath);
90 |
91 | self.utils.normalize(srcPath, function(err, file) {
92 | file.container = clientOpts.container;
93 | next(err, file, readStream);
94 | });
95 | }
96 | });
97 | },
98 |
99 | /*
100 | * Lists all files in directory path
101 | *
102 | * file: string or object
103 | * next: function(string err, array files)
104 | */
105 |
106 | list: function() {
107 |
108 | var file = arguments[0],
109 | filePath = ((typeof file === 'object') ? file.localpath : file),
110 | next = arguments[arguments.length-1],
111 | local = new FsProto({data_dir: this.opts.data_dir});
112 |
113 | local.list(file, next);
114 | },
115 |
116 | /*
117 | * Removes file from filesystem and CDN
118 | *
119 | * file: string or object
120 | * next: function(string err, boolean success)
121 | */
122 |
123 | remove: function() {
124 | var self = this;
125 | if (client && arguments[0] && typeof arguments[0] === 'string' && typeof arguments[arguments.length-1] === 'function') {
126 | var container = (arguments[1] && typeof arguments[1] === 'string' ? arguments[1] : self.opts.container);
127 | client.removeFile(container, arguments[0], arguments[arguments.length-1]);
128 | }
129 | },
130 |
131 | utils: require('./utils')
132 |
133 | };
134 |
135 | module.exports = CDNProto;
136 |
--------------------------------------------------------------------------------
/src/modules/cdn/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "provider" : "",
3 | "data_dir" : "",
4 | "username" : "",
5 | "apiKey" : "",
6 | "container" : ""
7 | }
8 |
--------------------------------------------------------------------------------
/src/modules/cdn/fs.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | imagemagick = require('imagemagick'),
3 | multer = require('multer'),
4 | mime = require('mime'),
5 | path = require('path'),
6 | regex = /[^\\/]+\.[^\\/]+$/,
7 | Stream = require('stream')
8 | zlib = require('zlib');
9 |
10 | function FsProto(options) {
11 | this.dataDir = path.resolve((0 === options.data_dir.indexOf('/') ? options.data_dir : options.basePath + '/../' + options.data_dir));
12 | this.tmpDir = options.data_dir + '/tmp';
13 | this.permDir = options.data_dir + '/perm';
14 | };
15 |
16 | FsProto.prototype = {
17 |
18 | /*
19 | * Saves a file from a string or readStream, and returns file object
20 | *
21 | * dest: string or object
22 | * source: string or readStream
23 | * options: object [optional]
24 | * next: function(string err, object file)
25 | */
26 |
27 | save: function() {
28 |
29 | var self = this,
30 | dest = arguments[0],
31 | source = arguments[1],
32 | buffer = ((arguments[1] instanceof Buffer) ? arguments[1] : null)
33 | options = (arguments[2] ? arguments[2] : null),
34 | next = arguments[arguments.length-1],
35 | compress = options && options.compress,
36 | append = options && options.append,
37 | header = options && options.header,
38 | write = options && options.write,
39 | encoding = ((options && options.encoding) ? options.encoding : null),
40 | destPath = ((typeof dest === 'object') ? dest.localpath : dest),
41 | rootDir = ((options && options.persist) ? self.permDir : self.tmpDir),
42 | writeOptions = {};
43 |
44 | if (compress) {
45 | destPath += '.zip';
46 | }
47 |
48 | if (append) {
49 | writeOptions.flags = 'a';
50 | }
51 |
52 | if (buffer) {
53 | var readStream = null
54 | }
55 | else {
56 | var readStream = ((typeof source === 'string') ? fs.createReadStream(source) : source);
57 | readStream.pause();
58 | }
59 |
60 | self.utils.parse_path(destPath, rootDir, function(err, path) {
61 |
62 | if (err) {
63 | next(err);
64 | }
65 |
66 | (function(next) {
67 | var writeStream = fs.createWriteStream(path, writeOptions);
68 |
69 | if (header) {
70 | var headerStream = new Stream();
71 | headerStream.on('data', function(data) {
72 | writeStream.write(data);
73 | });
74 |
75 | headerStream.emit('data', options.header);
76 | }
77 |
78 | writeStream.on('error', next);
79 | writeStream.on('finish', function(err) {
80 |
81 | if (err) next(err);
82 | else self.utils.normalize(path, next);
83 | });
84 |
85 | if (compress) {
86 | var gzip = zlib.createGzip();
87 | readStream.pipe(gzip).pipe(writeStream);
88 | readStream.resume();
89 | }
90 | else if (readStream) {
91 | readStream.pipe(writeStream);
92 | readStream.resume();
93 | }
94 |
95 | if (buffer) {
96 | writeStream.write(encoding ? buffer : buffer.toString(), encoding, function() {
97 | writeStream.end();
98 | });
99 | }
100 | })(next);
101 |
102 | });
103 | },
104 |
105 |
106 | /*
107 | * Saves an avatar file
108 | *
109 | * fileName: string
110 | * source: string. image location | url
111 | * dstPath: string
112 | * next: function(string err, string dstFile)
113 | */
114 | saveAvatar: function() {
115 | var self = this,
116 | fileName = arguments[0],
117 | source = arguments[1],
118 | dstPath = arguments[2],
119 | next = arguments[3];
120 |
121 | var dstFile = dstPath + fileName + '.png';
122 |
123 | self.save(dstFile, source, { persist : true }, function(err, file) {
124 | if (err) {
125 | next(err);
126 | } else {
127 | var options = {
128 | srcPath : file.localpath,
129 | dstPath : file.localpath.replace(/\.[a-z]{0,4}$/i, '.png'),
130 | format: 'png',
131 | height: 125,
132 | width: 125
133 | };
134 |
135 | imagemagick.convert([options.srcPath, '-resize', '125x125', options.dstPath], function(err, result) {
136 | if (err) {
137 | next(err);
138 | } else {
139 | next(err, dstFile);
140 | }
141 | });
142 | }
143 | });
144 |
145 | },
146 |
147 |
148 | /*
149 | * Gets a file from a fileStruct and returns a new fileStruct and readStream
150 | *
151 | * source: string or object
152 | * next: function(string err, object file, readStream)
153 | */
154 |
155 | get: function() {
156 |
157 | var self = this,
158 | source = arguments[0],
159 | options = (arguments[1] ? arguments[1] : null),
160 | rootDir = ((options && options.persist) ? self.permDir : self.tmpDir),
161 | next = arguments[arguments.length-1],
162 | srcPath = ((typeof source === 'object') ? source.localpath : rootDir + source),
163 | readStream = fs.createReadStream(srcPath);
164 |
165 | self.utils.normalize(srcPath, function(err, struct) {
166 | if (source.name) {
167 | struct.name = source.name;
168 | }
169 |
170 | next(err, struct, readStream);
171 | });
172 | },
173 |
174 | /*
175 | * Lists all files in directory path
176 | *
177 | * file: string or object
178 | * next: function(string err, array files)
179 | */
180 |
181 | list: function() {
182 |
183 | var file = arguments[0],
184 | filePath = ((typeof file === 'object') ? file.localpath : file),
185 | next = arguments[arguments.length-1];
186 |
187 | if (filePath.match(regex)) next("list() cannot be called on files, only directories.");
188 |
189 | fs.exists(filePath, function(exists) {
190 | if (exists) {
191 | fs.readdir(filePath, function (err, files) {
192 | if (err) next(err);
193 |
194 | var results = [];
195 |
196 | files.map(function (file) {
197 | return path.join(filePath, file);
198 | }).filter(function (file) {
199 | return fs.statSync(file).isFile();
200 | }).forEach(function (file) {
201 | (self.utils.normalize(file.name, function(err, fileStruct) {
202 | results.push(fileStruct)
203 | }))(results, filePath)
204 | });
205 |
206 | next(null, results)
207 | });
208 | }
209 | else {
210 | next("Directory does not exist.");
211 | }
212 | });
213 | },
214 |
215 | /*
216 | * Removes file from filesystem
217 | *
218 | * file: string or object
219 | * options: object
220 | * next: function(string err, boolean success)
221 | */
222 |
223 | remove: function() {
224 |
225 | var file = arguments[0],
226 | filePath = ((typeof file === 'object') ? file.localpath : file),
227 | options = (arguments[1] ? arguments[1] : null),
228 | rootDir = ((options && options.persist) ? self.permDir : self.tmpDir),
229 | next = arguments[arguments.length-1];
230 |
231 | fs.exists(rootDir + filePath, function(exists) {
232 | if (exists) fs.unlink(filePath, next);
233 | else next("File does not exist.");
234 | });
235 | },
236 |
237 | /*
238 | * Finds file in filesystem
239 | *
240 | * file: string or object
241 | * next: function(string err, object file)
242 | */
243 |
244 | find: function() {
245 |
246 | var file = arguments[0],
247 | self = this,
248 | filePath = ((typeof file === 'object') ? file.localpath : file),
249 | next = arguments[arguments.length-1];
250 |
251 | fs.exists(filePath, function(exists) {
252 | if (exists) self.utils.normalize(filePath, next);
253 | else next("File does not exist.");
254 | });
255 | },
256 |
257 | utils: require('./utils')
258 |
259 | };
260 |
261 | module.exports = FsProto;
262 |
--------------------------------------------------------------------------------
/src/modules/cdn/index.js:
--------------------------------------------------------------------------------
1 | var CDNProto = require('./src/cdn.js');
2 | var FsProto = require('./src/fs.js');
3 |
4 | function Fs_Cdn(options) {
5 | if (options && options.hasOwnProperty("provider") && options.hasOwnProperty("data_dir")) {
6 | this.prototype = CDNProto.prototype;
7 | return new CDNProto(options);
8 | }
9 | else if (options && options.hasOwnProperty("data_dir")) {
10 | this.prototype = FsProto.prototype;
11 | return new FsProto(options);
12 | }
13 | else throw new Error("Required options not specified in config.")
14 | };
15 |
16 | module.exports = Fs_Cdn;
--------------------------------------------------------------------------------
/src/modules/cdn/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fs-cdn",
3 | "version": "0.0.3",
4 | "description": "An adapter between fs and pkgcloud",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha --timeout 10000"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/wotio/fs-cdn"
12 | },
13 | "author": "Alfonso Gober ",
14 | "license": "Apache",
15 | "bugs": {
16 | "url": "https://github.com/wotio/fs-cdn/issues"
17 | },
18 | "homepage": "https://github.com/wotio/fs-cdn",
19 | "devDependencies": {
20 | "mocha": "latest",
21 | "should": "^4.0.4"
22 | },
23 | "dependencies": {
24 | "async": "^0.9.0",
25 | "mime": "^1.2.11",
26 | "multer": "^0.1.6",
27 | "pkgcloud": "latest",
28 | "mkdirp": ">=0.3.5"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/modules/cdn/utils.js:
--------------------------------------------------------------------------------
1 | var mkdirp = require('mkdirp'),
2 | multer = require('multer'),
3 | path = require('path');
4 |
5 | module.exports = {
6 | HTTPFormHandler : function() {
7 | return multer({
8 | dest : this.tmpDir,
9 | onFileUploadComplete : function(file) {
10 | file.localpath = file.path;
11 | file.name = file.originalname;
12 | file.type = file.mimetype;
13 | }
14 | });
15 | },
16 |
17 | parse_path: function(relPath, root, next) {
18 | var relPathRegexp = /\.\./g,
19 | mode = null, // @todo permissions mask?
20 | localPath = path.resolve( (root + '/' + relPath).replace(relPathRegexp, '')),
21 | basePath = path.dirname(localPath);
22 |
23 | mkdirp(basePath, mode, function(err) {
24 | next(err, localPath);
25 | });
26 | },
27 |
28 | gzip_compress: function() {
29 | console.log("Hi");
30 | },
31 |
32 | get_filename_from_path: function(path) {
33 | return path.split('\\').pop().split('/').pop();
34 | },
35 |
36 | normalize: function(filePath, next) {
37 | var self = this;
38 |
39 | fs.stat(filePath, function(err, stats) {
40 | if (err) {
41 | next(err);
42 | } else {
43 | next(null, {
44 | size : stats.size,
45 | localpath : filePath,
46 | name : self.get_filename_from_path(filePath),
47 | type : mime.lookup(filePath),
48 | encoding : 'binary'
49 | });
50 | }
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/worker.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 |
21 | /**
22 | * Dedicated worker
23 | */
24 | process.env.WORKER = true;
25 |
26 | var bootstrap = require(__dirname + '/bootstrap'),
27 | app = bootstrap.app,
28 | helper = require('./lib/helper'),
29 | cluster = require('cluster');
30 |
31 | // export app everywhere
32 | module.exports.app = app;
33 |
34 | //
35 | // ------ START CLUSTER
36 | //
37 |
38 | app.logmessage('BIPIO_WORKER:STARTED:' + new Date());
39 |
40 | if (cluster.isMaster) {
41 | // when user hasn't explicitly configured a cluster size, use 1 process per cpu
42 | var forks = GLOBAL.CFG.server.forks ? GLOBAL.CFG.server.forks : require('os').cpus().length;
43 | app.logmessage('Node v' + process.versions.node);
44 | app.logmessage('Starting ' + forks + ' fork(s)');
45 |
46 | for (var i = 0; i < forks; i++) {
47 | cluster.fork();
48 | }
49 |
50 | cluster.on('disconnect', function(worker) {
51 | app.logmessage('Worker:' + worker.workerID + ':Disconnect');
52 | cluster.fork();
53 | });
54 |
55 | } else {
56 |
57 | workerId = cluster.worker.workerID;
58 |
59 | helper.tldtools.init(
60 | function() {
61 | app.logmessage('TLD:UP');
62 | },
63 | function(body) {
64 | app.logmessage('TLD:Cache fail - ' + body, 'error')
65 | }
66 | );
67 | }
68 |
69 | app.logmessage('WAITING...');
70 |
--------------------------------------------------------------------------------
/tests/lib/helper.js:
--------------------------------------------------------------------------------
1 | process.HEADLESS = true
2 |
3 | var bootstrap = require(__dirname + '/../../src/bootstrap'),
4 | assert = require('assert'),
5 | should = require('should');
6 |
7 | describe('helper', function() {
8 | it('can get the bipio favicon', function(done) {
9 | app.helper.resolveFavicon('https://bip.io/docs/pods', function(err, url, suffix, hashedIco) {
10 | url.should.equal('https://bip.io/favicon.ico')
11 | done();
12 | });
13 |
14 | });
15 |
16 | // arbitrary - this could change at any time :D :D
17 | it('can get icon from link in page', function(done) {
18 | app.helper.resolveFavicon('https://evernote.com/', function(err, url, suffix, hashedIco) {
19 | url.should.equal('https://evernote.com/media/img/favicon.ico')
20 | done();
21 | });
22 | });
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/tests/managers/dao-mongo.js:
--------------------------------------------------------------------------------
1 | var bootstrap = require(__dirname + '/../../src/bootstrap'),
2 | dao = bootstrap.app.dao,
3 | assert = require('assert'),
4 | should = require('should'),
5 | uuid = require('node-uuid'),
6 | accountInfo;
7 |
8 | describe('bootstrap', function() {
9 | it('can bootstrap', function(done) {
10 | this.timeout(0);
11 | dao.on('ready', function() {
12 | done();
13 | });
14 | });
15 |
16 | it('can copy a collection', function(done) {
17 | dao.copyTo('bips', 'pod_syndication_dups', function() {
18 | console.log(arguments);
19 | done();
20 | })
21 | });
22 | });
--------------------------------------------------------------------------------
/tests/managers/dao.js:
--------------------------------------------------------------------------------
1 | var bootstrap = require(__dirname + '/../../src/bootstrap'),
2 | dao = bootstrap.app.dao,
3 | assert = require('assert'),
4 | should = require('should'),
5 | uuid = require('node-uuid'),
6 | accountInfo;
7 |
8 | describe('bootstrap', function() {
9 | it('can bootstrap', function(done) {
10 | this.timeout(0);
11 | dao.on('ready', function() {
12 | done();
13 | });
14 | });
15 |
16 | it('has queues', function(done) {
17 | this.timeout(0);
18 | bootstrap.app.bastion.on('readyQueue', function(queueName) {
19 | if ('queue_jobs' === queueName) {
20 | done();
21 | }
22 | });
23 | });
24 |
25 | it('can compile a token authenticated accountInfo object', function(done) {
26 | dao.checkAuth(
27 | GLOBAL.CFG.testing_user.username,
28 | GLOBAL.CFG.testing_user.password,
29 | 'token',
30 | function(err, acct) {
31 | if (err) {
32 | done(err);
33 | } else {
34 | acct.should.be.ok;
35 | acct.user.username.should.equal(GLOBAL.CFG.testing_user.username);
36 |
37 | // assert expected object structure and interface
38 | acct.should.have.ownProperty('user');
39 | acct.user.should.have.ownProperty('id');
40 | acct.user.settings.should.be.a('object');
41 |
42 | acct.user.domains.should.be.a('object');
43 | acct.user.domains.set.should.be.a('function');
44 | acct.user.domains.get.should.be.a('function');
45 | acct.user.domains.test.should.be.a('function');
46 |
47 | acct.user.channels.should.be.a('object');
48 | acct.user.channels.set.should.be.a('function');
49 | acct.user.channels.get.should.be.a('function');
50 | acct.user.channels.test.should.be.a('function');
51 |
52 | Object.keys(acct.user.domains).should.not.be.empty;
53 |
54 | accountInfo = acct;
55 | done();
56 | }
57 | }
58 | );
59 | });
60 |
61 | it('can compile a domain accountInfo object', function(done) {
62 | dao.domainAuth('admin.localhost', true,
63 | function(err, acct) {
64 | if (err) {
65 | err.should.not.be.ok;
66 | done();
67 | } else {
68 |
69 | console.log(acct);
70 |
71 | acct.should.be.ok;
72 | acct.user.username.should.equal(GLOBAL.CFG.testing_user.username);
73 |
74 | // assert expected object structure and interface
75 | acct.should.have.ownProperty('user');
76 | acct.user.should.have.ownProperty('id');
77 | acct.user.settings.should.be.a('object');
78 |
79 | acct.user.domains.should.be.a('object');
80 | acct.user.domains.set.should.be.a('function');
81 | acct.user.domains.get.should.be.a('function');
82 | acct.user.domains.test.should.be.a('function');
83 |
84 | acct.user.channels.should.be.a('object');
85 | acct.user.channels.set.should.be.a('function');
86 | acct.user.channels.get.should.be.a('function');
87 | acct.user.channels.test.should.be.a('function');
88 |
89 | Object.keys(acct.user.domains).should.not.be.empty;
90 |
91 | accountInfo = acct;
92 | done();
93 | }
94 | }
95 | );
96 | });
97 |
98 | /*
99 | it('can compile a domain/authenticated accountInfo object', function(done) {
100 | dao.checkAuth(
101 | GLOBAL.CFG.testing_user.username,
102 | GLOBAL.CFG.testing_user.password,
103 | 'token',
104 | function(err, acct) {
105 | if (err) {
106 | done(err);
107 | } else {
108 | acct.should.be.ok;
109 | acct.user.username.should.equal(GLOBAL.CFG.testing_user.username);
110 |
111 | // assert expected object structure and interface
112 | acct.should.have.ownProperty('user');
113 | acct.user.should.have.ownProperty('id');
114 | acct.user.settings.should.be.a('object');
115 |
116 | acct.user.domains.should.be.a('object');
117 | acct.user.domains.set.should.be.a('function');
118 | acct.user.domains.get.should.be.a('function');
119 | acct.user.domains.test.should.be.a('function');
120 |
121 | acct.user.channels.should.be.a('object');
122 | acct.user.channels.set.should.be.a('function');
123 | acct.user.channels.get.should.be.a('function');
124 | acct.user.channels.test.should.be.a('function');
125 |
126 | Object.keys(acct.user.domains).should.not.be.empty;
127 |
128 | accountInfo = acct;
129 | done();
130 | }
131 | }
132 | );
133 | });
134 | */
135 | });
136 |
137 |
138 | /*
139 | describe('bips', function() {
140 | it('can save a bip', function(done) {
141 | this.timeout(0);
142 |
143 | var bip = {
144 | type : 'http',
145 | hub : {
146 | source : {
147 | // edges : [ cid ]
148 | edges : [ '88013839-3932-4083-ae67-fb02f3f32b92' ]
149 |
150 | }
151 | }
152 | },
153 | model = dao.modelFactory('bip', bip, accountInfo, true);
154 | dao.create(model, function(err, result) {
155 | console.log(err);
156 | console.log(result);
157 | done(!err && result);
158 | }, accountInfo);
159 | });
160 | });
161 | */
162 | describe('retrieve a pod', function() {
163 | it('contains expected attributes', function(done) {
164 | dao.pod('facebook').should.have.ownProperty('_description');
165 | dao.pod('facebook').should.have.ownProperty('_description');
166 | done();
167 | });
168 | });
--------------------------------------------------------------------------------
/tests/migrations/0.3.0.js:
--------------------------------------------------------------------------------
1 | var path = require('path'),
2 | app = require(__dirname + '/../../src/bootstrap').app,
3 | targetConfig = path.resolve( process.env.NODE_CONFIG_DIR || path.join(__dirname, '/../../config/'), 'test.json'),
4 | migration = require(__dirname + '/../../migrations/0.3.0'),
5 | assert = require('assert'),
6 | should = require('should');
7 |
8 | describe('Migration', function() {
9 | describe('Successfully migrates to v0.3.0', function() {
10 | if (!process.env.NODE_ENV === 'test') throw new Error("NODE_ENV must be set to `test` to run migration tests! Please run `export NODE_ENV=test` and then `make install`. During install, set the name of your db to something OTHER THAN `bipio` (so as not to interfere with any existing installations). Then re-run this migration test.");
11 | it('Setup', function(done){
12 | var config = JSON.parse(fs.readFileSync(targetConfig));
13 | if (!config.hasOwnProperty("cdn")) config.cdn = "test/cdn/dir";
14 | if (!config.hasOwnProperty("datadir")) config.datadir = "test/data/dir";
15 | fs.writeFile(targetConfig, JSON.stringify(config, null, 2), done);
16 | });
17 |
18 | it('Creates 500 pod_syndication_track_subscribe entries with current timestamps', function(done) {
19 | for (var i=1; i<=500; i++) {
20 | (function(isLast) {
21 | app.dao.create(app.dao.modelFactory('pod_syndication_track_subscribe', {
22 | owner_id : Math.random().toString(36).slice(2),
23 | channel_id : Math.random().toString(36).slice(2),
24 | created: new Date().getTime(),
25 | guid : Math.random().toString(36).slice(2),
26 | bip_id : Math.random().toString(36).slice(2),
27 | last_update : new Date().getTime()
28 | }),
29 | function(err, modelName, retModel, code) {
30 | if (err) throw new Error(err);
31 | if (isLast) done();
32 | });
33 | })(i === 500);
34 | }
35 | });
36 |
37 | it('Creates 500 pod_syndication_track_subscribe entries with 90-day-old timestamps', function(done) {
38 | for (var i=1; i<=500; i++) {
39 | (function(isLast) {
40 | app.dao.create(app.dao.modelFactory('pod_syndication_track_subscribe', {
41 | owner_id : Math.random().toString(36).slice(2),
42 | channel_id : Math.random().toString(36).slice(2),
43 | created: new Date().getTime() - (90 * 24 * 60 * 60 * 1000),
44 | guid : Math.random().toString(36).slice(2),
45 | bip_id : Math.random().toString(36).slice(2),
46 | last_update : new Date().getTime()
47 | }),
48 | function(err) {
49 | if (err) throw new Error(err);
50 | if (isLast) done();
51 | });
52 | })(i === 500);
53 | }
54 | });
55 |
56 | it('Creates 500 pod_soundcloud_track_favorite entries with current timestamps', function(done) {
57 | for (var i=1; i<=500; i++) {
58 | (function(isLast) {
59 | app.dao.create(app.dao.modelFactory('pod_soundcloud_track_favorite', {
60 | owner_id : Math.random().toString(36).slice(2),
61 | channel_id : Math.random().toString(36).slice(2),
62 | created: new Date().getTime(),
63 | track_id : Math.random().toString(36).slice(2),
64 | bip_id : Math.random().toString(36).slice(2),
65 | last_update : new Date().getTime()
66 | }),
67 | function(err) {
68 | if (err) throw new Error(err);
69 | if (isLast) done();
70 | });
71 | })(i === 500);
72 | }
73 | });
74 |
75 | it('Creates 500 pod_soundcloud_track_favorite entries with 90-day-old timestamps', function(done) {
76 | for (var i=1; i<=500; i++) {
77 | (function(isLast) {
78 | app.dao.create(app.dao.modelFactory('pod_soundcloud_track_favorite', {
79 | owner_id : Math.random().toString(36).slice(2),
80 | channel_id : Math.random().toString(36).slice(2),
81 | created: new Date().getTime() - (90 * 24 * 60 * 60 * 1000),
82 | track_id : Math.random().toString(36).slice(2),
83 | bip_id : Math.random().toString(36).slice(2),
84 | last_update : new Date().getTime()
85 | }),
86 | function(err) {
87 | if (err) throw new Error(err);
88 | if (isLast) done();
89 | });
90 | })(i === 500);
91 | }
92 | });
93 |
94 | it('Runs the migration', function(done) {
95 | migration.run(app, targetConfig, function(err) {
96 | if (err) throw new Error(err);
97 | done();
98 | });
99 | });
100 |
101 | it('Checks for the existence of 500 pod_syndication_dup entries', function(done) {
102 | app.dao.findFilter('pod_syndication_dup', {}, function(err, result) {
103 | if (err) throw new Error(err);
104 | should.exist(result);
105 | result.should.have.length(500)
106 | done();
107 | });
108 | });
109 |
110 | it('Checks for the existence of 500 pod_soundcloud_dup entries', function(done) {
111 | app.dao.findFilter('pod_soundcloud_dup', {}, function(err, result) {
112 | if (err) throw new Error(err);
113 | should.exist(result);
114 | result.should.have.length(500)
115 | done();
116 | });
117 | });
118 |
119 | it('Checks test.json for removal of `cdn` and `datadir` properties', function() {
120 | var newConfig = JSON.parse(fs.readFileSync(targetConfig));
121 | newConfig.should.not.have.property("cdn");
122 | newConfig.should.not.have.property("datadir");
123 | });
124 |
125 | it('Cleans up test data', function(done) {
126 | app.dao.removeFilter('pod_syndication_dup', {}, function(err, result) {
127 | if (err) console.log(err);
128 | app.dao.removeFilter('pod_soundcloud_dup', {}, function(err, result) {
129 | if (err) console.log(err);
130 | app.dao.removeFilter('pod_syndication_track_subscribe', {}, function(err, result) {
131 | if (err) console.log(err);
132 | app.dao.removeFilter('pod_soundcloud_track_favorite', {}, function(err, result) {
133 | if (err) console.log(err);
134 | done();
135 | });
136 | });
137 | });
138 | });
139 | });
140 | });
141 | });
--------------------------------------------------------------------------------
/tests/models/domain.js:
--------------------------------------------------------------------------------
1 | var bootstrap = require(__dirname + '/../../src/bootstrap'),
2 | dao = bootstrap.app.dao,
3 | assert = require('assert'),
4 | should = require('should'),
5 | uuid = require('node-uuid'),
6 | accountInfo,
7 | domainPublic = GLOBAL.CFG.domain_public.split(':').shift();
8 |
9 | describe('bootstrap', function() {
10 | it('can compile an accountInfo object', function(done) {
11 | dao.checkAuth(
12 | GLOBAL.CFG.testing_user.username,
13 | GLOBAL.CFG.testing_user.password,
14 | 'token',
15 | function(err, acct) {
16 | if (err) {
17 | done(err);
18 | } else {
19 | acct.should.be.ok;
20 | acct.user.username.should.equal(GLOBAL.CFG.testing_user.username);
21 |
22 | // assert expected object structure and interface
23 | acct.should.have.ownProperty('user');
24 | acct.user.should.have.ownProperty('id');
25 | acct.user.settings.should.be.a('object');
26 |
27 | acct.user.domains.should.be.a('object');
28 | acct.user.domains.set.should.be.a('function');
29 | acct.user.domains.get.should.be.a('function');
30 | acct.user.domains.test.should.be.a('function');
31 |
32 | acct.user.channels.should.be.a('object');
33 | acct.user.channels.set.should.be.a('function');
34 | acct.user.channels.get.should.be.a('function');
35 | acct.user.channels.test.should.be.a('function');
36 |
37 | Object.keys(acct.user.domains).should.not.be.empty;
38 |
39 | accountInfo = acct;
40 | done();
41 | }
42 | }
43 | );
44 | });
45 | });
46 |
47 | describe('domains', function() {
48 | /*
49 | it('can save a localhost domain', function(done) {
50 | var domainStruct = {
51 | name : uuid.v4() + '.localhost',
52 | type : 'custom'
53 | },
54 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
55 | dao.create(model, function(err, modelName, domain) {
56 | modelName.should.equal('domain');
57 |
58 | domain.should.have.ownProperty('id');
59 | domain.should.have.ownProperty('owner_id');
60 | domain.should.have.ownProperty('type');
61 | domain.should.have.ownProperty('name');
62 | domain.should.have.ownProperty('_available');
63 |
64 | domain.owner_id.should.equal(accountInfo.user.id);
65 | domain.name.should.equal(domainStruct.name);
66 | domain.type.should.equal('custom');
67 |
68 | domain._available.should.be.true;
69 | done();
70 | }, accountInfo);
71 | });*/
72 |
73 | it('can save a non-local domain as unverified', function(done) {
74 | var domainStruct = {
75 | name : uuid.v4() + '.localhost.net'
76 | },
77 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
78 | dao.create(model, function(err, modelName, domain) {
79 | modelName.should.equal('domain');
80 |
81 | domain.should.have.ownProperty('id');
82 | domain.should.have.ownProperty('owner_id');
83 | domain.should.have.ownProperty('type');
84 | domain.should.have.ownProperty('name');
85 | domain.should.have.ownProperty('_available');
86 |
87 | domain.owner_id.should.equal(accountInfo.user.id);
88 | domain.name.should.equal(domainStruct.name);
89 | domain.type.should.equal('custom');
90 |
91 | domain._available.should.be.false;
92 |
93 | done();
94 | }, accountInfo);
95 | });
96 |
97 | it('can not save *.local domains of type vanity', function(done) {
98 | var domainStruct = {
99 | name : uuid.v4() + '.' + domainPublic,
100 | type : 'vanity'
101 | },
102 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
103 | dao.create(model, function(err, modelName, result, status) {
104 | result.should.have.property('status');
105 | result.should.have.property('message');
106 | result.status.should.equal(400);
107 |
108 | result.message.should.equal('ValidationError');
109 | result.errors.should.have.property('name');
110 | done();
111 | });
112 | });
113 |
114 | it('can detect local domains', function(done) {
115 | var domainStruct = {
116 | name : domainPublic + uuid.v4()
117 | }
118 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
119 | model.isLocal(domainStruct.name).should.equal(false);
120 | model.isLocal('testing.' + domainPublic).should.equal(true);
121 | done();
122 | });
123 |
124 | it('verfies localhost', function(done) {
125 | var domainStruct = {
126 | name : 'localhost'
127 | }
128 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
129 | model.verify(accountInfo, function(err) {
130 | err.should.be.false;
131 | model._available.should.be.true;
132 |
133 | done();
134 | });
135 | });
136 |
137 |
138 | it('verfies a correctly bound domain', function(done) {
139 | var domainStruct = {
140 | name : 'testing.bip.io'
141 | }
142 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
143 | model.verify(
144 | {
145 | user : accountInfo.user,
146 | getDefaultDomain : function() {
147 | return {
148 | name : 'bip.io'
149 | }
150 | }
151 | },
152 | function(err) {
153 | err.should.be.false;
154 | model._available.should.be.true;
155 |
156 | done();
157 | }
158 | );
159 | });
160 |
161 | it('should fail verifying an unknown domain', function(done) {
162 | var domainStruct = {
163 | name : uuid.v4() + '.com.net.eu'
164 | }
165 | model = dao.modelFactory('domain', domainStruct, accountInfo, true);
166 | model.verify(
167 | {
168 | user : accountInfo.user,
169 | getDefaultDomain : function() {
170 | return {
171 | name : domainPublic
172 | }
173 | }
174 | },
175 | function(err, model, result) {
176 | console.log(err);
177 | err.should.have.ownProperty('errno');
178 | err.errno.should.equal('ENODATA');
179 | result._available.should.be.false;
180 | done();
181 | }
182 | );
183 | });
184 | });
--------------------------------------------------------------------------------
/tools/archive_logs.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * archives active bip_logs table >=2 months old into namespaced table names of bip_logs_YYYYMM
5 | * and drops from bip_logs.
6 | *
7 | * This is a heavy operation, handle with care
8 | *
9 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
10 | *
11 | * Licensed under the Apache License, Version 2.0 (the "License");
12 | * you may not use this file except in compliance with the License.
13 | * You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | *
23 | */
24 | process.HEADLESS = true;
25 | process.NOCONSUME = true;
26 |
27 | var bootstrap = require(__dirname + '/../src/bootstrap'),
28 | moment = require('moment'),
29 | dao = bootstrap.app.dao,
30 | Q = require('q'),
31 | _ = require('underscore'),
32 | monthAge = 2;
33 |
34 | dao.on('ready', function(dao) {
35 |
36 | // get max and min
37 | dao.aggregate(
38 | 'bip_log',
39 | [{
40 | $group: {
41 | _id: "$item",
42 | maxCreated: { $max: "$created" },
43 | minCreated: { $min: "$created" }
44 | }
45 | }],
46 | function(err, result) {
47 | if (err) {
48 | console.error(err);
49 | } else if (result.length) {
50 |
51 | //result[0].minCreated = 1431128106615;
52 | //monthAge = 0;
53 |
54 | // create date promises
55 | var max = result[0].maxCreated,
56 | min = result[0].minCreated,
57 | realMax = moment().subtract(monthAge, 'months').endOf('month').valueOf(),
58 | realMin = moment(min),
59 | year, month,
60 | minYear, maxYear
61 | promises = {};
62 |
63 | if (max > realMax) {
64 | max = realMax;
65 | }
66 |
67 | minYear = moment(min).get('year');
68 | maxYear = moment(max).get('year');
69 |
70 | minMonth = moment(min).get('month');
71 | maxMonth = moment(max).get('month');
72 |
73 | // shard into months
74 | month = ++maxMonth;
75 |
76 | for (var i = maxYear; i >= minYear; i--) {
77 | for (; month > 0; month--) {
78 |
79 | promises[i * 100 + month] = Q.defer();
80 |
81 | if (i == minYear && month == minMonth) {
82 | break;
83 | }
84 |
85 | if (1 == month) {
86 | month = 12;
87 | break;
88 | }
89 | }
90 | }
91 |
92 | Q.all(
93 | _.pluck(
94 | _.values(
95 | promises
96 | ),
97 | 'promise'
98 | )
99 | ).then(
100 | // accept
101 | function(results) {
102 | console.log(results.join());
103 |
104 | process.exit(0);
105 | },
106 |
107 | // reject
108 | function() {
109 | console.error(arguments);
110 | process.exit(0);
111 | }
112 | );
113 |
114 | _.each(promises, function(promise, yearMonth) {
115 | var ym = moment(yearMonth, 'YYYYMM'),
116 | from = ym.startOf('month').valueOf(),
117 | to = ym.endOf('month').valueOf(),
118 | filter =
119 | {
120 | created: {
121 | $gte : from,
122 | $lte : to
123 | }
124 | };
125 |
126 | console.log('ARCHIVING ' + yearMonth)
127 |
128 | // do not overwrite into collection which already has records
129 | // ... manually remove records if you need to regenerate the data.
130 | dao.getConnection().collection('bip_logs_' + yearMonth).count({}, function(err, count) {
131 | if (err) {
132 | promise.reject(err);
133 | } else if (count) {
134 | promise.resolve('SKIPPING ' + yearMonth);
135 | } else if (!count) {
136 | dao.getConnection().collection('bip_logs').aggregate(
137 | [
138 | {
139 | $match: filter
140 | },
141 | {
142 | $out: "bip_logs_" + yearMonth
143 | }
144 | ],
145 | function(err) {
146 | if (err) {
147 | promise.reject(err);
148 | } else {
149 | //promise.resolve('DONE ' + yearMonth );
150 | //return;
151 | // cleanup
152 | console.log('CLEANING UP ' + yearMonth)
153 | dao.removeFilter('bip_log', filter, function(err) {
154 | if (err) {
155 | promise.reject(err);
156 | } else {
157 | promise.resolve('DONE ' + yearMonth );
158 | }
159 | });
160 | }
161 | }
162 | );
163 | }
164 | });
165 | });
166 | }
167 | });
168 | });
169 |
170 |
--------------------------------------------------------------------------------
/tools/avsnarf.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | var dao = require('../src/bootstrap');
24 | var request = require('request');
25 |
26 | // given an image url and account id, attaches the account avatar
27 | var ownerId = process.argv[2];
28 | url = process.argv[3],
29 | dstPath = process.argv[4] ? process.argv[4] : GLOBAL.CFG.datadir + '/perm/cdn/img/av/'
30 |
31 | if (!url || !ownerId) {
32 | console.log('Usage : node avsnarf.js {owner id} {url} {destination path}');
33 | process.exit(1);
34 | }
35 |
36 | url = request.get(url);
37 |
38 | console.log('fetching avatar...');
39 | dao.app.modules.cdn.saveAvatar(ownerId, url, dstPath, function(err, response) {
40 | if (!err) {
41 | console.log("OK!");
42 | console.log(response);
43 | } else {
44 | console.log(response);
45 | console.log('Error');
46 | }
47 | process.exit(0);
48 | });
49 |
--------------------------------------------------------------------------------
/tools/bip-expire.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Expires bips which have reached their end-life by time
25 | */
26 | process.HEADLESS = true;
27 | var bootstrap = require(__dirname + '/../src/bootstrap');
28 | bootstrap.app.dao.expireAll(function(err, msg) {
29 | if (err) {
30 | console.log('ERROR:' + err);
31 | console.log(msg);
32 | } else {
33 | console.log('DONE');
34 | }
35 |
36 | process.exit(0);
37 | });
38 |
--------------------------------------------------------------------------------
/tools/bip-trigger.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Triggers unpaused trigger bips.
25 | */
26 | process.HEADLESS = true;
27 | var bootstrap = require(__dirname + '/../src/bootstrap');
28 | bootstrap.app.bastion.on('readyQueue', function(readyQueue) {
29 | if (readyQueue == 'queue_jobs') {
30 | app.logmessage('BIP-TRIGGER:Trigger Queue Discovered:queue_jobs');
31 | bootstrap.app.dao.triggerAll(function(err, msg) {
32 | if (err) {
33 | app.logmessage('BIP-TRIGGER:' + err + ' ' + msg);
34 | } else {
35 | app.logmessage(msg);
36 | app.logmessage('BIP-TRIGGER:DONE');
37 | }
38 | process.exit(0);
39 | });
40 | }
41 | });
--------------------------------------------------------------------------------
/tools/cdnfactory.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | var dao = require('../src/bootstrap');
24 |
25 | // given a url, downloads the favicon for the domain into our icofactory CDN
26 | var url = process.argv[2],
27 | bipid = process.argv[3];
28 |
29 | if (!url) {
30 | console.log('Usage : node cdnfactory.js {url} {bip id optional}');
31 | process.exit(1);
32 | }
33 |
34 | console.log('fetching icon...');
35 | dao.getBipRefererIcon(bipid, url, true, function(err, response) {
36 | if (!err) {
37 | console.log("OK!");
38 | console.log(response);
39 | } else {
40 | console.log(response);
41 | console.log('Error');
42 | }
43 | process.exit(0);
44 | });
45 |
--------------------------------------------------------------------------------
/tools/create_user.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | process.HEADLESS = true;
4 | if (!process.argv[3]) {
5 | console.log('Usage - create_user {username} {email} {password} {account_level}');
6 | process.exit(0);
7 | }
8 |
9 | var username = process.argv[2],
10 | email = process.argv[3],
11 | password = process.argv[4],
12 | accountLevel = process.argv[5]
13 | bootstrap = require(__dirname + '/../src/bootstrap'),
14 | dao = bootstrap.app.dao;
15 |
16 | dao.on('ready', function(dao) {
17 | dao.createUser(username, email, password, function() {
18 | console.log(arguments);
19 | process.exit(0);
20 | }, accountLevel || GLOBAL.DEFS.ACCOUNT_LEVEL.USER);
21 | });
22 |
--------------------------------------------------------------------------------
/tools/crypt_get.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | var crypto = require('crypto');
3 |
4 | process.HEADLESS = true;
5 |
6 | var cryptStr = process.argv[2],
7 | bootstrap = require(__dirname + '/../src/bootstrap');
8 |
9 | function AESDecrypt(cryptedStr, autoPadding) {
10 | var crypted = new Buffer(cryptedStr, 'base64').toString('utf-8');
11 | var keyVersion = crypted.substr(0, 1),
12 | iv = crypted.substr(1, 16),
13 | key = CFG.k[keyVersion],
14 | cypher = crypted.substr(17);
15 |
16 | var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
17 |
18 | if (!autoPadding) {
19 | autoPadding = false;
20 | }
21 | decipher.setAutoPadding(autoPadding);
22 |
23 | var decrypted = (decipher.update(cypher, 'base64', 'ascii') + decipher.final('ascii'));
24 | return decrypted;
25 | }
26 |
27 | console.log(AESDecrypt(cryptStr));
--------------------------------------------------------------------------------
/tools/gencert.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -x
3 | #
4 | # Installs a self signed cert for orgname into an install directory
5 | #
6 |
7 | CN=$1
8 | INSTALL_DIR=$2
9 |
10 | cd $2
11 |
12 | openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
13 |
14 | openssl rsa -passin pass:x -in server.pass.key -out server.key
15 |
16 | rm server.pass.key
17 |
18 | openssl req -new -key server.key -out server.csr \
19 | -subj "/C=US/ST=NY/L=NY/O=WOTIO/OU=BIPIO/CN=$CN"
20 |
21 | openssl x509 -req -in server.csr -signkey server.key -out server.crt
--------------------------------------------------------------------------------
/tools/generate-hub-stats.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Forces a builds active hub/edges stats for today for every user.
25 | * The system will otherwise automatically generate these stats once per day.
26 | */
27 |
28 | process.HEADLESS = true;
29 | var bootstrap = require(__dirname + '/../src/bootstrap');
30 | bootstrap.app.dao.generateHubStats(function(err, msg) {
31 | if (err) {
32 | app.logmessage('THERE WERE ERRORS');
33 | } else {
34 | app.logmessage(msg);
35 | app.logmessage('DONE');
36 | }
37 | process.exit(0);
38 | });
--------------------------------------------------------------------------------
/tools/git-setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd )"
4 | GITDIR=$BASEDIR/.git
5 |
6 | if [ -a $GITDIR ]; then
7 | mkdir -p $GITDIR/hooks
8 |
9 | # add post-merge
10 | cp $BASEDIR/tools/post-merge $GITDIR/hooks
11 | chmod ug+x $GITDIR/hooks/post-merge
12 | fi
--------------------------------------------------------------------------------
/tools/heapdump.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Sends a heapdump packet to target pid via bastion
25 | */
26 |
27 | process.HEADLESS = true;
28 | if (!process.argv[2]) {
29 | console.log('Usage - heapdump {pid}');
30 | process.exit(0);
31 | }
32 |
33 | var pid = process.argv[2]
34 | bootstrap = require(__dirname + '/../src/bootstrap'),
35 |
36 | bootstrap.app.bastion.on('readyQueue', function(readyQueue) {
37 | if (readyQueue == 'queue_jobs') {
38 | bootstrap.app.bastion.createJob(
39 | DEFS.JOB_HEAP_DUMP,
40 | {
41 | pid : Number(pid),
42 | key : CFG.dumpKey
43 | }
44 | );
45 |
46 | //queues don't receipt delivery so wait arbitrarily and close out
47 | setTimeout(function() {
48 | process.exit(0);
49 | }, 1000)
50 | }
51 | });
--------------------------------------------------------------------------------
/tools/init-boilerplate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4 | NAME=$1
5 | LABEL=$2
6 |
7 | if [ $NAME ]; then
8 |
9 | TARGETDIR="$BASEDIR/../node_modules/bip-pod-$NAME"
10 |
11 | if [ -d $TARGETDIR ]; then
12 | echo "Target pod directory $TARGETDIR already exists"
13 | exit 0
14 | fi
15 |
16 | BOILERDIR="$BASEDIR/../node_modules/bip-pod/boilerplate"
17 | if [ ! -d $BOILERDIR ]; then
18 | echo "Source Boilerplate directory $BOILERDIR could not be found"
19 | exit 0
20 | fi
21 |
22 | mkdir $TARGETDIR
23 | cp $BOILERDIR/* $TARGETDIR
24 | cd $TARGETDIR
25 | echo 'node_modules' > .gitignore
26 |
27 | TITLE=$NAME
28 |
29 | if [ $LABEL ]; then
30 | TITLE=$LABEL
31 | fi
32 |
33 | p1="s/boilerplate/${NAME}/g"
34 | p2="s/Boilerplate/${TITLE}/g"
35 |
36 | perl -pi -e $p1 *
37 | perl -pi -e $p2 *
38 |
39 | mv boilerplate.png $NAME.png
40 |
41 | echo 'Done'
42 |
43 | else
44 | echo 'Usage : ./tools/init-boilerplate.sh {pod-name}'
45 | fi
46 |
47 |
--------------------------------------------------------------------------------
/tools/login_set.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Sets an explicit password for an account id
25 | */
26 |
27 | process.HEADLESS = true;
28 | if (!process.argv[3]) {
29 | console.log('Usage - token_set {account uuid} {password}');
30 | process.exit(0);
31 | }
32 |
33 | var accountId = process.argv[2],
34 | token = process.argv[3],
35 | bootstrap = require(__dirname + '/../src/bootstrap'),
36 | dao = bootstrap.app.dao,
37 | modelName = 'account_auth';
38 |
39 | dao.on('ready', function(dao) {
40 | dao.find(
41 | modelName,
42 | {
43 | owner_id : accountId,
44 | type : 'login_primary'
45 | },
46 | function(err, result) {
47 | if (err || !result) {
48 | console.log(err);
49 | if (!result) {
50 | console.log('account id not found');
51 | }
52 | process.exit(0);
53 | } else {
54 | result.password = token;
55 |
56 | dao.updateProperties(
57 | modelName,
58 | result.id,
59 | {
60 | password : token
61 | },
62 | function(err, result) {
63 | if (err) {
64 | console.log(err);
65 | console.log(result);
66 | } else {
67 | console.log('new token : ' + token)
68 | console.log('done');
69 | }
70 | process.exit(0);
71 | }
72 | );
73 | }
74 | }
75 | );
76 | });
77 |
--------------------------------------------------------------------------------
/tools/oauth_refresh.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Triggers unpaused trigger bips.
25 | */
26 | process.HEADLESS = false;
27 | process.NOCONSUME = true;
28 |
29 | var bootstrap = require(__dirname + '/../src/bootstrap'),
30 | dao = bootstrap.app.dao;
31 |
32 | dao.on('ready', function(dao) {
33 | dao.refreshOAuth(function(err) {
34 | console.log(arguments);
35 | if (err) {
36 | console.error(err);
37 | } else {
38 | console.log('done');
39 | process.exit(0);
40 | }
41 | });
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/tools/pause_bip.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /*
24 | * Pauses a bip by id
25 | */
26 |
27 | process.NOCONSUME = true;
28 | process.REQ_PODS = "email";
29 |
30 | var bootstrap = require(__dirname + '/../src/bootstrap'),
31 | dao = bootstrap.app.dao,
32 | bipId = process.argv[2],
33 | reason = process.argv[3];
34 |
35 | if (!bipId) {
36 | console.log('Usage - ./tools/pause_bip.js {bip_id} "reason" (optional)');
37 | process.exit();
38 | }
39 |
40 | function pauseBip(id, reason, next) {
41 | dao.find(
42 | 'bip',
43 | {
44 | id : id
45 | },
46 | function(err, bip) {
47 | if (err) {
48 | next(err);
49 |
50 | } else if (bip) {
51 | var message = reason || 'Paused By Administrator',
52 | pod = dao.pod('email');
53 |
54 | if (pod && pod.getConfig().sender) {
55 | message += ' - Please Contact ' + pod.getConfig().sender + ' for more info';
56 | }
57 |
58 | dao.pauseBip(bip, true, function(err) {
59 | if (err) {
60 | next(err);
61 | } else {
62 |
63 | var jobPacket = {
64 | owner_id : bip.owner_id,
65 | bip_id : bip.id,
66 | code : 'bip_paused_manual',
67 | message : message
68 | };
69 |
70 | app.bastion.createJob(DEFS.JOB_BIP_ACTIVITY, jobPacket, function() {
71 | next();
72 | });
73 | }
74 | }
75 | );
76 |
77 | } else {
78 | next('Not Found');
79 | }
80 | }
81 | );
82 | }
83 |
84 | dao.on('ready', function(dao) {
85 | pauseBip(bipId, reason, function(err) {
86 | if (err) {
87 | console.error(err);
88 | } else {
89 | console.log('ok');
90 | }
91 | process.exit(0);
92 | });
93 | });
--------------------------------------------------------------------------------
/tools/post-merge:
--------------------------------------------------------------------------------
1 | #/usr/bin/env bash
2 | # MIT © Sindre Sorhus - sindresorhus.com
3 | # via https://gist.github.com/sindresorhus/7996717
4 |
5 | changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
6 |
7 | check_run() {
8 | echo "$changed_files" | grep --quiet "$1" && eval "$2"
9 | }
10 |
11 | check_run package.json "npm install"
12 |
--------------------------------------------------------------------------------
/tools/rm_user.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Removes a user by UUID
25 | */
26 |
27 | var async = require('async');
28 |
29 | process.HEADLESS = true;
30 | if (!process.argv[2]) {
31 | console.log('Usage - rm_user {account uuid}');
32 | process.exit(0);
33 | }
34 |
35 | var accountId = process.argv[2],
36 | bootstrap = require(__dirname + '/../src/bootstrap'),
37 | dao = bootstrap.app.dao,
38 | acctSearch = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(accountId),
39 | emailSearch = -1 !== accountId.indexOf('@');
40 |
41 | function accountQuery(accountId) {
42 | dao.removeUser(
43 | accountId,
44 | function(err, result) {
45 | if (err || !result) {
46 | console.log(err);
47 | if (!result) {
48 | console.log('account id not found');
49 | }
50 | process.exit(0);
51 | } else {
52 | console.log('removed user');
53 | process.exit(0);
54 | }
55 | }
56 | );
57 | }
58 |
59 | dao.on('ready', function(dao) {
60 | if (acctSearch) {
61 | accountQuery(accountId);
62 | } else {
63 | var filter = {};
64 | if (emailSearch) {
65 | filter.email_account = accountId;
66 | } else {
67 | filter.username = accountId;
68 | }
69 |
70 | dao.find(
71 | 'account',
72 | filter,
73 | function(err, result) {
74 | if (err || !result) {
75 | if (!result) {
76 | console.log('account id not found');
77 | }
78 | process.exit(0);
79 | } else {
80 | accountQuery(result.id);
81 | }
82 | }
83 | );
84 | }
85 | });
--------------------------------------------------------------------------------
/tools/set_user_level.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Sets a user's level by username or account id
25 | */
26 |
27 | process.HEADLESS = true;
28 |
29 | var accountId = process.argv[2],
30 | level = process.argv[3],
31 | bootstrap = require(__dirname + '/../src/bootstrap'),
32 | dao = bootstrap.app.dao,
33 | modelName = 'account_auth',
34 | acctSearch = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(accountId),
35 | emailSearch = -1 !== accountId.indexOf('@');
36 |
37 | function showUsage() {
38 | var levels = 'admin|user';
39 |
40 | if (app.modules.permissions) {
41 | levels = Object.keys(GLOBAL.CFG.modules.permissions.config.plans).join('|')
42 | }
43 |
44 | console.log('Usage - token_get {account uuid|user_name|email address} (' + levels + ')');
45 | process.exit(0);
46 | }
47 |
48 | if (!process.argv[2]) {
49 | showUsage();
50 | }
51 |
52 | dao.on('ready', function(dao) {
53 | var levelOK = false;
54 | for (var k in GLOBAL.DEFS.ACCOUNT_LEVEL) {
55 | if (level === GLOBAL.DEFS.ACCOUNT_LEVEL[k]) {
56 | levelOK = true;
57 | break;
58 | }
59 | }
60 |
61 | if (!levelOK) {
62 | console.error('Unknown Account Level');
63 | showUsage();
64 | } else {
65 |
66 | if (acctSearch) {
67 | accountQuery(accountId);
68 | } else {
69 | var filter = {};
70 | if (emailSearch) {
71 | filter.email_account = accountId;
72 | } else {
73 | filter.username = accountId;
74 | }
75 |
76 | dao.find(
77 | 'account',
78 | filter,
79 | function(err, result) {
80 | if (err || !result) {
81 | if (!result) {
82 | console.log('account id not found');
83 | }
84 | process.exit(0);
85 | } else {
86 | dao.updateColumn('account', result.id, { account_level : level }, function() {
87 | if (err) {
88 | console.error(err);
89 | } else {
90 | console.log('Account Level ' + level + ' Set For ' + result.id);
91 | }
92 | process.exit(0);
93 | });
94 | }
95 | }
96 | );
97 | }
98 | }
99 | });
--------------------------------------------------------------------------------
/tools/test_jwt_token.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Creates a testable X-JWT-Signature header for BipIO
25 | */
26 |
27 | var jwt = require('jsonwebtoken'),
28 | fs = require('fs'),
29 | path = require('path'),
30 | configPath,
31 | config,
32 | expireMinutes,
33 | options = {},
34 | appEnv = process.env.NODE_ENV;
35 |
36 | if (appEnv === 'development' || !appEnv) {
37 | appEnv = 'default';
38 | }
39 |
40 | configPath = path.resolve(
41 | process.env.NODE_CONFIG_DIR || path.join(__dirname, '../config/'),
42 | appEnv + '.json'
43 | );
44 |
45 | config = JSON.parse(fs.readFileSync(configPath));
46 |
47 | if (!process.argv[2]) {
48 | console.log('Usage - test_jwt_token payload (expiryMinutes)');
49 | process.exit(0);
50 | }
51 |
52 | if (process.argv[3]) {
53 | options.expiresInMinutes = process.argv[3];
54 | }
55 |
56 | console.log(jwt.sign(JSON.parse(process.argv[2]), config.jwtKey, options));
--------------------------------------------------------------------------------
/tools/token_get.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Gets a token by account uuid
25 | */
26 |
27 | process.HEADLESS = true;
28 | if (!process.argv[2]) {
29 | console.log('Usage - token_get {account uuid|user_name}');
30 | process.exit(0);
31 | }
32 |
33 | var accountId = process.argv[2],
34 | bootstrap = require(__dirname + '/../src/bootstrap'),
35 | dao = bootstrap.app.dao,
36 | modelName = 'account_auth',
37 | acctSearch = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(accountId),
38 | emailSearch = -1 !== accountId.indexOf('@');
39 |
40 | function accountQuery(accountId, username) {
41 | dao.find(
42 | modelName,
43 | {
44 | owner_id : accountId,
45 | type : 'token'
46 | },
47 | function(err, result) {
48 | if (err || !result) {
49 | console.log(err);
50 | if (!result) {
51 | console.log('account id not found');
52 | }
53 | process.exit(0);
54 | } else {
55 | if (username) {
56 | console.log('Username : ' + username)
57 | }
58 | console.log('Token : ' + dao.modelFactory(modelName, result).getPassword());
59 | process.exit(0);
60 | }
61 | }
62 | );
63 | }
64 |
65 | dao.on('ready', function(dao) {
66 | if (acctSearch) {
67 | accountQuery(accountId);
68 | } else {
69 | var filter = {};
70 | if (emailSearch) {
71 | filter.email_account = accountId;
72 | } else {
73 | filter.username = accountId;
74 | }
75 |
76 | dao.find(
77 | 'account',
78 | filter,
79 | function(err, result) {
80 | if (err || !result) {
81 | if (!result) {
82 | console.log('account id not found');
83 | }
84 | process.exit(0);
85 | } else {
86 | accountQuery(result.id, result.username);
87 | }
88 | }
89 | );
90 | }
91 | });
92 |
--------------------------------------------------------------------------------
/tools/token_regen.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Regenerates a token for an account id
25 | */
26 |
27 | process.HEADLESS = true;
28 | if (!process.argv[2]) {
29 | console.log('Usage - token_regen {account uuid}');
30 | process.exit(0);
31 | }
32 |
33 | var accountId = process.argv[2],
34 | crypto = require('crypto'),
35 | bootstrap = require(__dirname + '/../src/bootstrap'),
36 | dao = bootstrap.app.dao,
37 | modelName = 'account_auth';
38 |
39 | dao.on('ready', function(dao) {
40 | dao.regenToken(accountId, function(err, token) {
41 | if (err) {
42 | console.log(err);
43 | console.log(result);
44 | } else {
45 | console.log('new token : ' + token)
46 | console.log('done');
47 | process.exit(0);
48 | }
49 | });
50 | });
--------------------------------------------------------------------------------
/tools/token_set.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Sets an explicit token for an account id
25 | */
26 |
27 | process.HEADLESS = true;
28 | if (!process.argv[3]) {
29 | console.log('Usage - token_set {account uuid} {token}');
30 | process.exit(0);
31 | }
32 |
33 | var accountId = process.argv[2],
34 | token = process.argv[3],
35 | bootstrap = require(__dirname + '/../src/bootstrap'),
36 | dao = bootstrap.app.dao,
37 | modelName = 'account_auth';
38 |
39 | if (token.length > 32) {
40 | console.log('Token Must be 32 Bytes');
41 | process.exit(0);
42 | }
43 |
44 | dao.on('ready', function(dao) {
45 | dao.find(
46 | modelName,
47 | {
48 | owner_id : accountId,
49 | type : 'token'
50 | },
51 | function(err, result) {
52 | if (err || !result) {
53 | console.log(err);
54 | if (!result) {
55 | console.log('account id not found');
56 | }
57 | process.exit(0);
58 | } else {
59 | result.password = token;
60 |
61 | dao.updateProperties(
62 | modelName,
63 | result.id,
64 | {
65 | password : token
66 | },
67 | function(err, result) {
68 | if (err) {
69 | console.log(err);
70 | console.log(result);
71 | } else {
72 | console.log('new token : ' + token)
73 | console.log('done');
74 | }
75 | process.exit(0);
76 | }
77 | );
78 | }
79 | }
80 | );
81 | });
82 |
--------------------------------------------------------------------------------
/tools/triage.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | var bootstrap = require(__dirname + '/../src/bootstrap'),
24 | dao = bootstrap.app.dao,
25 | fs = require('fs');
26 |
27 | function getDisposition(obj) {
28 | var dispotion;
29 | if (obj.required) {
30 | disposition = obj.required.slice(0);
31 | } else {
32 | disposition = [];
33 | }
34 |
35 | for (var k in obj.properties) {
36 | if (obj.properties.hasOwnProperty(k)) {
37 | if (-1 === disposition.indexOf(k)) {
38 | disposition.push(k);
39 | }
40 | }
41 | }
42 |
43 | return disposition;
44 |
45 | }
46 |
47 |
48 | dao.on('ready', function(dao) {
49 | dao.describe('pod', null, function(err, modelName, results) {
50 | var mPath,
51 | mBody,
52 | s, ds, keys,
53 | action,
54 | podActual,
55 | disposition,
56 | initOAuthConfigs = [ 'clientID', 'clientSecret', 'consumerKey', 'consumerSecret' ];
57 |
58 | // write manifest for each pod
59 | for (var podName in results) {
60 | if (results.hasOwnProperty(podName)) {
61 | // if ('syndication' === podName) {
62 | mPath = GLOBAL.SERVER_ROOT + '/../node_modules/bip-pod-' + podName + '/bpm.json';
63 |
64 | s = results[podName];
65 | podActual = dao.pod(podName);
66 |
67 | // cleanup
68 | for (r in s.renderers) {
69 | if (s.renderers.hasOwnProperty(r)) {
70 | s.renderers[r].title = s.renderers[r].description
71 |
72 | delete s.renderers[r]._href;
73 | delete s.renderers[r].description;
74 | }
75 | }
76 |
77 | mBody = {
78 | name : s.name,
79 | title : s.title,
80 | description : s.description,
81 | url : '',
82 | trackDuplicates : podActual._trackDuplicates, // inspect pod
83 | config : app._.clone(podActual.getConfig()),
84 | auth : {
85 | strategy : s.auth.type
86 | },
87 | rpcs : s.renderers,
88 | actions : s.actions
89 | };
90 |
91 | if (podActual._dataSources.length) {
92 | mBody.dataSources = {};
93 | for (var i = 0; i < podActual._dataSources.length; i++) {
94 | ds = podActual._dataSources[i];
95 |
96 |
97 | app._.each(ds.entitySchema, function(schema) {
98 | if (schema.type.Inflector) {
99 | schema.type = 'string';
100 | } else if (/Number/.test(schema.type)) {
101 | schema.type = 'number';
102 |
103 | } else if (/Mixed/.test(schema.type)) {
104 | schema.type = 'mixed';
105 |
106 | } else if (/Object/.test(schema.type)) {
107 | schema.type = 'object';
108 |
109 | } else if (/Array/.test(schema.type)) {
110 | schema.type = 'array';
111 |
112 | } else if (/Boolean/.test(schema.type)) {
113 | schema.type = 'boolean';
114 |
115 | } else {
116 | console.log(schema.type, schema.type instanceof String);
117 | process.exit(0);
118 | }
119 | });
120 |
121 | mBody.dataSources[ds.entityName.replace('pod_' + s.name + '_', '')] =
122 | {
123 | properties : ds.entitySchema,
124 | keys : ds.compoundKeyConstraints ? Object.keys(ds.compoundKeyConstraints) : [ ds.entityIndex ]
125 | };
126 | }
127 | }
128 |
129 |
130 | //console.log(s);
131 | // console.log(podActual._dataSources);
132 | //console.log(mBody.dataSources);
133 | //process.exit(0);
134 |
135 | if ('oauth' === s.auth.type) {
136 | if (mBody.config.oauth) {
137 | for (var o in mBody.config.oauth) {
138 | if (-1 !== initOAuthConfigs.indexOf(o)) {
139 | mBody.config.oauth[o] = '';
140 | }
141 | }
142 | }
143 |
144 | } else if ('issuer_token' === s.auth.type) {
145 | mBody.auth.authMap = s.authMap
146 | }
147 |
148 | // cleanup actions
149 | delete mBody.auth.type;
150 |
151 | for (var a in s.actions) {
152 | if (s.actions.hasOwnProperty(a)) {
153 | action = s.actions[a];
154 |
155 | if (action.trigger) {
156 | action.trigger = action.socket ? 'realtime' : 'poll';
157 | } else {
158 | action.trigger = 'invoke';
159 | }
160 |
161 | // config
162 | if (Object.keys(action.config.properties).length) {
163 | action.config.disposition = getDisposition(action.config);
164 | }
165 | delete action.config['$schema'];
166 |
167 | // imports
168 | if (Object.keys(action.imports.properties).length) {
169 | action.imports.disposition = getDisposition(action.imports);
170 | }
171 | delete action.imports['$schema'];
172 |
173 | // exports
174 | delete action.exports['$schema'];
175 |
176 |
177 | // deprecated attributes
178 | delete action.singleton;
179 | delete action.auto;
180 | delete action.defaults;
181 | delete action.socket;
182 | delete action.auth_required;
183 |
184 | if (Object.keys(action.renderers).length) {
185 | action.rpcs = app._.clone(action.renderers);
186 | // normalize rpc attributes
187 | app._.each(action.rpcs, function(rpc) {
188 | rpc.title = rpc.description;
189 | rpc.description = rpc.description_long;
190 | delete rpc.description_long;
191 | });
192 | }
193 |
194 | delete action.renderers;
195 |
196 | }
197 | }
198 |
199 | console.log('----------------');
200 | console.log('wrote ' + mPath);
201 | // console.log(mBody);
202 | // console.log(mBody.actions.send);
203 |
204 | fs.writeFileSync(mPath , JSON.stringify(mBody, null, 2));
205 |
206 | }
207 | }
208 |
209 | process.exit(0);
210 | });
211 | });
212 |
--------------------------------------------------------------------------------
/tools/update-transforms.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | *
4 | * The Bipio API Server
5 | *
6 | * Copyright (c) 2017 InterDigital, Inc. All Rights Reserved
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | *
21 | * A Bipio Commercial OEM License may be obtained via hello@bip.io
22 | */
23 | /**
24 | * Updates System Transforms.
25 | */
26 | process.HEADLESS = true;
27 | var bootstrap = require(__dirname + '/../src/bootstrap');
28 | bootstrap.app.dao.on('ready', function(read) {
29 | // if (GLOBAL.CFG.updateTransforms) {
30 | app.logmessage('DAO:Updating System Transforms');
31 | bootstrap.app.dao.reduceTransformDefaults(function(err, msg) {
32 | if (err) {
33 | app.logmessage('DAO:' + err + ' ' + msg);
34 | } else {
35 | app.logmessage('DAO:Updating System Transforms:Done');
36 | }
37 | process.exit(0);
38 | });
39 | // }
40 | });
41 |
--------------------------------------------------------------------------------