Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
chrispahm committed Apr 12, 2019
0 parents commit ee04c71
Show file tree
Hide file tree
Showing 12 changed files with 1,470 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
18 changes: 18 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
parserOptions: {
ecmaVersion: 2017
},
env: {
es6: true,
node: true
},
extends: [
'plugin:prettier/recommended'
],
plugins: [
'prettier'
],
rules: {
'no-console': 'off'
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
credentials.js
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"semi": false,
"singleQuote": true
}
9 changes: 9 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
MIT License

Copyright (c) 2019 Christoph Pahmeyer

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

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 365FarmNet Connect - Node.js client
A simple promise based client for the [365FarmNet Connect REST API](https://developer.365farmnet.com/).

## Quick start
```
npm install 365farmnet
```
**Note:** This library requires Node.js > v.10.0

Import the library, and pass the partner ID and secret that you got from
registering at [https://devcon.365farmnet.com/](https://devcon.365farmnet.com/).

```js
const farmnet = require('365farmnet')({
partnerId: 'yourPartnerId',
secret: 'yourPartnerSecret'
})
```

Make requests to the 365FarmNet Connect REST API by calling the imported function
(`farmnet` if you follow this example) in the following manner:

```js
// farmnettoken is the JWT that is passed to the iframe within the
// 365FarmNet main application
farmnet('fields', {
token: farmnettoken,
params: {
includeGeometry: false,
includeSoilType: true
}
}).then(data => {
// data will contain all fields of the farm
}).catch(err => {
console.log(err)
})

```

## API
The module exports a default function.
It takes two arguments:

### `farmnet('endpoint', options)`
| Name | Description |
|:--------------------------------------|:-------------------------------------------------------------------------------------|
| **endpoint** *string* *required* | The REST API endpoint to call. See documentation for all available endpoints. |
| **options.token** *string* *required* | The `token` property of the `options object` needs to be a valid JWT `farmnettoken`. |
| **options.params** *object* | Optional query params for the API call. |
| **options.data** *object* | Optional body params for the API call (for POST/PUT requests). |
| **options.method** *string* | Default: 'GET'. Can be any HTTP request method valid for the given endpoint. |

### Testing
You need to put a `credentials.js` file in the root of the directory containing your 365FarmNet partnerId, secret, and a valid JWT token for testing.
Example:
```js
// content of the credentials.js file, which needs to be placed at the root of this repo
module.exports = {
partnerId: 'your_partner_id',
secret: 'your_secret',
farmnettoken: 'paste_jwt_token_here'
}
```

Then run
```
npm test
```

### Contribution
Please feel free to submit an issue or a pull request!

### License
MIT
99 changes: 99 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
'use strict'

const fs = require('fs')
const util = require('util')
const jwt = require('jsonwebtoken')
const axios = require('axios')

const verify = util.promisify(jwt.verify)
const sign = util.promisify(jwt.sign)
const readFile = util.promisify(fs.readFile)

module.exports = function(credentials) {
if (!credentials || !credentials.partnerId || !credentials.secret)
throw Error('No partner id or secret.')

async function request(endpoint, options) {
try {
// check if options were passed correctly
checkQuery(endpoint, options)
const partnerToken = await getPartnerToken(options.token)
const apiBase = getApiBase(options.token)
let method = 'GET'
if (options.method) method = options.method
const url = `${apiBase}/connect/v1/${endpoint}`

const query = {
method,
url,
params: options.params,
data: options.data,
headers: {
Authorization: `Bearer ${partnerToken}`
}
}

const { data } = await axios(query)
return data
} catch (e) {
throw Error(e)
}
}

function checkQuery(endpoint, options) {
if (!endpoint) throw Error('No 365farment API endpoint specified.')
if (!options) throw Error('No 365farmnet query options passed.')
else if (!options.token) throw Error('No 365farmnet token passed.')
}

function getApiBase(farmnettoken) {
const decoded = jwt.decode(farmnettoken)
if (!decoded) throw Error('Invalid 365farmnet token.')
const apiBase = decoded['fn-ext'].apiBase
return apiBase
}

async function getPublicKey(farmnettoken) {
try {
const apiBase = getApiBase(farmnettoken)
let pemKey = 'development'
if (
apiBase === 'https://connect.365farmnet.com' ||
apiBase === 'https://pp-connect.365farmnet.com'
) {
pemKey = 'production'
}
// load development or production public key
const publicKey = await readFile(
`keys/365FarmNet_Connect-API_public_key_${pemKey}.pem`
)
return publicKey
} catch (e) {
throw Error(e)
}
}

async function getPartnerToken(farmnettoken) {
try {
const publicKey = await getPublicKey(farmnettoken)
await verify(farmnettoken, publicKey)
const payload = {
con: farmnettoken,
iss: credentials.partnerId
}
const options = {
expiresIn: '1d',
header: {
ver: '0.1',
type: 'partner'
}
}
const partnerToken = await sign(payload, credentials.secret, options)
return partnerToken
} catch (e) {
throw Error(e)
}
}

return request
}
14 changes: 14 additions & 0 deletions keys/365FarmNet_Connect-API_public_key_development.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3fGJsV7dGX/elR1x8eLn
10ohRXTsqYRa169AK3htM3WednX1xQuVRSRdxOdKFohvAf62VS8fO4+t8tAKJuxV
b61UXpyGGCg50u1MDFs7ZkeW7Dv/AByR838ZLnalpcDSO1EyJgmZeRbfIpAG0O27
8RuP5+wn/CtLc6tROYehsYf8VxQ8/+UScgM4C1fMFA19kZ3nEnz9fJrp33YPYouQ
CpCC/+ScRfbneplAtrR4dC1WcviV1DsA7lEqEJrWstOvSxQhQYuXa7QbnR8ya3Hu
UFAl2QUSoqa+DpigYSwKVE0KDD12Y6+qwf4PF3Qa+WQzP1D1F84UOPqC7khSjLkN
kKwcR9JsDREc3y8q6C3e5CTYQemIv2zJ0NaaASU1B4n4xHlJDXpBUaptdBf+7pe+
8QBRU9Pgb0DdSShNKo6gpOlx9wJQoJkn/AMD4GDRWMph6qc6dHoMAMspm6BYfSLW
cyzWv1KrYZA8rIraPh3lLNAJ1UJKTIEASVfrKQCuBB7sJqb3a1H6trQdec3ZzYL/
RnQ/D7VZu+x7ArLDGeKZo3PmTGGoQaZT9XwVkZRt7ffTDsKmp2PiNI3jSRO5rsYc
ccWatbo95KbquQWqTmCr7oVJoH1uOHW3UsXkHwQM/2pP2MMOO9ndeFyfZ02PP7xV
cOBQA0uGG5KhdAVVZwJBhl0CAwEAAQ==
-----END PUBLIC KEY-----
14 changes: 14 additions & 0 deletions keys/365FarmNet_Connect-API_public_key_production.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4fZ8T5DitZHxO+YFAk3j
VMkcEos48kGmaJymcDkgCZRgtxAgRbwh7CROvVswMnQAKeGdvxgAQcRow0+Pi7d9
PC6Je3R4u5zK2DLAq6U9LmpweuGBJljoTxu4I7B5oA+yLrYNZy4Ing3PdpqtC7uv
i/liifxYBvaAMk6+efaheXQ0x2PD85g1IHiKRapJbPl56F7ejaOrXdxXTujiLG0q
wjn44vB1KLEW9pNaRPEbNxK4h8oD+m6/ASc/K4DR6PHqeF2u2M6WmgcOw/UGtRSc
WlGO1B6TrjQ9ew5chT0NE8WXze74HO6IjfeQJ259KUf0ChHbQYaYdgwb5B/m21+r
e9P0cdt1u/dTftY37Tso7JN8kFYai3XroUw+LbJQD5J4pY0s1eAK+XyKDiYPpfBd
M+9Ib827crSOaqhaY3xmhg5pXb6JqUSZyzq4Y87EnkAiGU+J6Nrm4IaIz36jkXPn
ZttPOWa92sESlSTijk5JHcoxI4SSIvWaEV2Ak0pA5MpjDfCM6y6EzctMVFw6YfT9
7+w8/1mtF/6pxxCtR+WaTgEBgR3ZogoqyzuELEYbIrRVvUvwWjiGgrEmuZ8A+5ti
zHyOGUtshQWcXmRL5ts2BuNdea36nYjguJeatSAHe8v7KYqpBnoBF+HQI7S1lfAC
fsXzgfUdZbatqHUeyX/1qT0CAwEAAQ==
-----END PUBLIC KEY-----
Loading

0 comments on commit ee04c71

Please sign in to comment.