diff --git a/controller/Controller.class.php b/controller/Controller.class.php
index b721fff2..7f42aead 100644
--- a/controller/Controller.class.php
+++ b/controller/Controller.class.php
@@ -89,6 +89,10 @@ class Controller
$router->get(['/ios', 'get-ios'], 'DownloadActions::executeGet');
$router->get('/roadmap', 'ContentActions::executeRoadmap');
+ $router->get('/developer-program', 'AcquisitionActions::executeDeveloperProgram');
+ $router->post('/developer-program/post', 'AcquisitionActions::executeDeveloperProgramPost');
+ $router->get('/developer-program/callback', 'AcquisitionActions::executeDeveloperProgramGithubCallback');
+
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');
$router->post('/postcommit', 'OpsActions::executePostCommit');
diff --git a/controller/Session.class.php b/controller/Session.class.php
index 8d14fd2d..4291690f 100644
--- a/controller/Session.class.php
+++ b/controller/Session.class.php
@@ -6,6 +6,9 @@ class Session
KEY_DOWNLOAD_ALLOWED = 'beta_download_allowed2',
KEY_PREFINERY_USER_ID = 'prefinery_user_id',
KEY_PREFINER_USED_CUSTOM_CODE = 'prefinery_used_custom_code',
+ KEY_DEVELOPER_CREDITS_ERROR = 'developer_credits_error',
+ KEY_DEVELOPER_CREDITS_SUCCESS = 'developer_credits_success',
+ KEY_DEVELOPER_CREDITS_WALLET_ADDRESS = 'developer_credits_wallet_address',
KEY_LIST_SUB_ERROR = 'list_error',
KEY_USER_CULTURE = 'user_culture';
diff --git a/controller/action/AcquisitionActions.class.php b/controller/action/AcquisitionActions.class.php
index 148f5cc7..847d4d92 100644
--- a/controller/action/AcquisitionActions.class.php
+++ b/controller/action/AcquisitionActions.class.php
@@ -2,12 +2,13 @@
class AcquisitionActions extends Actions
{
+ const DEVELOPER_REWARD = 250;
+
public static function executeThanks()
{
return ['acquisition/thanks'];
}
-
public static function executeYouTubeSub()
{
if (!Request::isPost())
@@ -40,4 +41,138 @@ class AcquisitionActions extends Actions
}
return [$template];
}
+
+ public static function executeDeveloperProgram()
+ {
+ return ['acquisition/developer-program', [
+ 'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
+ 'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
+ 'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
+ ]];
+ }
+
+ public static function executeDeveloperProgramPost()
+ {
+ $walletAddress = trim(Request::getPostParam('wallet'));
+ Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, $walletAddress);
+
+ if (!$walletAddress)
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Please provide a wallet address.');
+ }
+ elseif (!preg_match('/^b[1-9A-HJ-NP-Za-km-z]{33}$/', $walletAddress))
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid wallet address.');
+ }
+ else
+ {
+ if (!Config::get('github_developer_credits_client_id'))
+ {
+ throw new Exception('no github client id');
+ }
+
+ $githubParams = [
+ 'client_id' => Config::get('github_developer_credits_client_id'),
+ 'redirect_uri' => Request::getHostAndProto() . '/developer-program/callback',
+ 'scope' => 'user:email',
+ 'allow_signup' => false
+ ];
+ return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($githubParams));
+ }
+ return Controller::redirect('/developer-program');
+ }
+
+ public static function executeDeveloperProgramGithubCallback()
+ {
+ $code = Request::getParam('code');
+ $walletAddress = Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS);
+
+ if (!$walletAddress)
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Your wallet address disappeared while authenticated with GitHub.');
+ }
+ elseif (!$code)
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.');
+ }
+ else
+ {
+ $authResponseData = Curl::post('https://github.com/login/oauth/access_token', [
+ 'code' => $code,
+ 'client_id' => Config::get('github_developer_credits_client_id'),
+ 'client_secret' => Config::get('github_developer_credits_client_secret')
+ ], [
+ 'headers' => ['Accept: application/json'],
+ 'json_response' => true
+ ]);
+ if (!$authResponseData || !isset($authResponseData['access_token']))
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.');
+ }
+ elseif (isset($authResponseData['error_description']))
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']);
+ }
+ else
+ {
+ $accessToken = $authResponseData['access_token'];
+ $userResponseData = Curl::get('https://api.github.com/user', [], [
+ 'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio'],
+ 'json_response' => true
+ ]);
+
+ if (date('Y-m-d', strtotime($userResponseData['created_at'])) > '2017-01-30')
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This GitHub account is too recent.');
+ }
+ else
+ {
+ $lockName = 'github_dev_credits_write';
+ $dataFile = ROOT_DIR . '/data/writeable/github_developer_credits';
+
+ $lock = Lock::getLock($lockName, true); // EXCLUSIVE LOCK. IF SENDING CREDITS IS SLOW, THIS COULD BLOCK USERS
+
+ $existing = is_file($dataFile) ? json_decode(file_get_contents($dataFile), true) : [];
+
+ if (isset($existing[$userResponseData['login']]))
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You account already received credits.');
+ }
+ else
+ {
+ list($code, $out, $err) =
+ Shell::exec('/usr/bin/lbrynet-cli send_amount_to_address amount=250 ' . escapeshellarg('address=' . $walletAddress));
+
+ if ($code != 0)
+ {
+ if (stripos($out, 'InsufficientFundsError') !== false)
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
+ 'Our wallet is running low on funds. Please ping jeremy@lbry.io so he can refill it, then try again.');
+ }
+ else
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
+ 'Failed to send credits. This is an error on our side. Please email jeremy@lbry.io if it persists.');
+ }
+ }
+ else
+ {
+ $existing[$userResponseData['login']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s')];
+ file_put_contents($dataFile, json_encode($existing));
+
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
+ 'Send credits to GitHub user ' . $userResponseData['login'] . ' (' . $userResponseData['email'] . ') at wallet address ' .
+ $walletAddress);
+
+ }
+ }
+
+ Lock::freeLock($lock);
+ $lock = null;
+ }
+ }
+ }
+ return Controller::redirect('/developer-program');
+ }
}
\ No newline at end of file
diff --git a/lib/tools/Lock.class.php b/lib/tools/Lock.class.php
new file mode 100644
index 00000000..4c5affbe
--- /dev/null
+++ b/lib/tools/Lock.class.php
@@ -0,0 +1,70 @@
+
+
+
+ false, 'isAbsolute' => false]) ?>
+
+
+
Developer Program
+
All developers with a GitHub account prior to January 31st, 2017 are eligible for free credits.
+
To claim your credits, enter a wallet address in the form below and authenticate with GitHub.
+
+ We will store your GitHub username and email address, but nothing else.
+
+
+
+
+
\ No newline at end of file
diff --git a/view/template/layout/basic.php b/view/template/layout/basic.php
index 849d24b3..6a6f254d 100644
--- a/view/template/layout/basic.php
+++ b/view/template/layout/basic.php
@@ -47,11 +47,9 @@
-
-
-
+
diff --git a/view/template/page/quickstart.php b/view/template/page/quickstart.php
new file mode 100644
index 00000000..dde43f94
--- /dev/null
+++ b/view/template/page/quickstart.php
@@ -0,0 +1,137 @@
+
+
+
+ false, 'isAbsolute' => false]) ?>
+
+ Quickstart
+ This step-by-step guide will have running LBRY and interacting with the API in just a few minutes.
+ This guide is for programmers and other technical users. For consumer usage of LBRY, please go here.
+ What's Covered
+
+ - Installation
+ - Running LBRY
+ - The API
+ - Credits
+ - Community & Issues
+
+
+ 1. Installation
+ The easiest way to install LBRY is to use a pre-packaged binary. We provide binaries for Windows, macOS, and Debian-based Linux.
+
+
+
+ macOS |
+ Linux |
+ Windows |
+
+
+
+
+ Download DMG |
+ Download DEB |
+ Download MSI |
+
+
+
+
+ If you prefer to compile from source or are not on one of the above operating systems, follow
+ this guide.
+
+
+
+ 2. Running LBRY
+
+ Launch the deamon to run as a background process:
+
+
+
+ lbrynet-daemon --no-launch
+
+
+ The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.
+
+
+ 3. The API
+
+ When running, the LBRY daemon provides a JSON-RPC server running at https://localhost:5279/lbryapi
.
+
+
+ It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests.
+
+
+ To verify the LBRY daemon is running correctly and responding to requests, run:
+
+ curl 'http://localhost:5279/lbryapi' --data '{"method":"status","params":[]}'
+[
+ {
+ "connection_status": {
+ "message": "No connection problems detected",
+ "code": "connected"
+ },
+ "is_first_run": false,
+ "is_running": true,
+ "blocks_behind": 0,
+ "startup_status": {
+ "message": "Started lbrynet",
+ "code": "started"
+ },
+ "lbry_id": "7J75jSuxU9eizREuxk1r"
+ }
+]
+ This makes it easy to interact with the LBRY API in the programming language of your choice. Here's another example:
+ curl 'http://localhost:5279/lbryapi' --data '{"method":"resolve_name","params":[{"name":"what"}]}'
+[
+ {
+ "ver": "0.0.3",
+ "description": "What is LBRY? An introduction with Alex Tabarrok",
+ "license": "LBRY inc",
+ "title": "What is LBRY?",
+ "author": "Samuel Bryan",
+ "language": "en",
+ "sources": {
+ "lbry_sd_hash": "d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b"
+ },
+ "content_type": "video\/mp4",
+ "nsfw": false,
+ "thumbnail": "https:\/\/s3.amazonaws.com\/files.lbry.io\/logo.png"
+ }
+]
+ LBRY can be used to build everything from a censorship-proof image host, to a store for 3D printing files, to distribute large files or datasets, or use cases even we can't imagine!
+ View Full API Documentation
+
+
+ 4. Getting Credits
+ Many actions, such as reserving a name or purchasing paid content, require credits.
+ To receive credits, first generate a wallet address:
+ curl 'http://localhost:5279/lbryapi' --data '{"method":"wallet_new_address","params":[]}'
+["bbFxRyWCFRkA9YcuuZD8nE7XTLUxYnddTs"]
+ Use this address to get credits in one of two ways:
+
+
+
4a) Receive Free Credits
+
+ All developers with a valid GitHub account are eligible to receive free credits.
+
+
Claim Your Free Credits
+
+
+
4b) Purchase Credits
+
+ Credits can be bought on a variety of exchanges.
+ After purchasing, send them to the address generated above.
+
+
+
+
+
+
+
+ Join our Slack Channel to interact with LBRY developers and other community members. Please visit the #dev room (note: this is not a default channel).
+
+
+ Visit our GitHub page to view the source code or report issues.
+
+
+
+
+
\ No newline at end of file
diff --git a/view/template/report/dmca.php b/view/template/report/dmca.php
index f406e38c..6011fc01 100644
--- a/view/template/report/dmca.php
+++ b/view/template/report/dmca.php
@@ -10,7 +10,7 @@
-
+