+24
-9
@@ -1,26 +1,41 @@
|
||||
#########################################################vvv
|
||||
# Basics
|
||||
# The following env vars are expected to exist.
|
||||
# Fill them in here, or make sure you provide them via
|
||||
# your deployment environment.
|
||||
#########################################################vvv
|
||||
PORT=3000
|
||||
POSTGRES_URL="postgres://localhost/speckle2"
|
||||
REDIS_URL="redis://localhost:6379"
|
||||
CANONICAL_URL="http://localhost:3000"
|
||||
SESSION_SECRET="-> FILL IN <-"
|
||||
|
||||
#########################################################vvv
|
||||
# Emails
|
||||
# Optional.
|
||||
#########################################################vvv
|
||||
SMTP_HOST="-> FILL IN <-"
|
||||
SMTP_PORT=587
|
||||
SMPT_USERNAME="-> FILL IN <-"
|
||||
SMPT_PASSWORD="-> FILL IN <-"
|
||||
|
||||
# Authentication Strategies
|
||||
#########################################################vvv
|
||||
# Auth strategies
|
||||
# At least one needs to be enabled!
|
||||
#########################################################vvv
|
||||
STRATEGY_LOCAL=true
|
||||
|
||||
STRATEGY_GITHUB=false
|
||||
GITHUB_CLIENT_ID="-> FILL IN <-"
|
||||
GITHUB_CLIENT_SECRET="-> FILL IN <-"
|
||||
# STRATEGY_GITHUB=false
|
||||
# GITHUB_CLIENT_ID="-> FILL IN <-"
|
||||
# GITHUB_CLIENT_SECRET="-> FILL IN <-"
|
||||
|
||||
STRATEGY_GOOGLE=false
|
||||
GOOGLE_CLIENT_ID="-> FILL IN <-"
|
||||
GOOGLE_CLIENT_SECRET="-> FILL IN <-"
|
||||
# STRATEGY_GOOGLE=false
|
||||
# GOOGLE_CLIENT_ID="-> FILL IN <-"
|
||||
# GOOGLE_CLIENT_SECRET="-> FILL IN <-"
|
||||
|
||||
# Telemetry
|
||||
TELEMETRY=true
|
||||
|
||||
#########################################################vvv
|
||||
# Tracing & co.
|
||||
#########################################################vvv
|
||||
# SENTRY_DSN="-> FILL IN <-"
|
||||
TELEMETRY=true
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
'use strict'
|
||||
|
||||
|
||||
let http = require( 'http' )
|
||||
const http = require( 'http' )
|
||||
const url = require( 'url' )
|
||||
let WebSocket = require( 'ws' )
|
||||
const WebSocket = require( 'ws' )
|
||||
const express = require( 'express' )
|
||||
const compression = require( 'compression' )
|
||||
const appRoot = require( 'app-root-path' )
|
||||
const logger = require( 'morgan-debug' )
|
||||
const bodyParser = require( 'body-parser' )
|
||||
const debug = require( 'debug' )
|
||||
|
||||
const Sentry = require( '@sentry/node' )
|
||||
const Tracing = require( '@sentry/tracing' )
|
||||
const SentryInit = require( `${appRoot}/logging` )
|
||||
|
||||
const { ApolloServer, ForbiddenError } = require( 'apollo-server-express' )
|
||||
|
||||
require( 'dotenv' ).config( { path: `${appRoot}/.env` } )
|
||||
@@ -26,6 +30,8 @@ let graphqlServer
|
||||
exports.init = async ( ) => {
|
||||
const app = express( )
|
||||
|
||||
SentryInit( app )
|
||||
|
||||
await knex.migrate.latest( )
|
||||
|
||||
if ( process.env.NODE_ENV !== 'test' ) {
|
||||
@@ -66,6 +72,9 @@ exports.init = async ( ) => {
|
||||
debug( `speckle:debug` )( 'ws on disconnect connect event' )
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require( `${appRoot}/logging/apolloPlugin` )
|
||||
],
|
||||
tracing: process.env.NODE_ENV === 'development'
|
||||
} )
|
||||
|
||||
@@ -121,6 +130,8 @@ exports.startHttp = async ( app ) => {
|
||||
graphqlServer.installSubscriptionHandlers( server )
|
||||
graphqlServer.applyMiddleware( { app: app } )
|
||||
|
||||
app.use( Sentry.Handlers.errorHandler( ) )
|
||||
|
||||
server.on( 'listening', ( ) => {
|
||||
debug( `speckle:startup` )( ` 🚀 My name is Spockle Server, and I'm running at ${server.address().port}` )
|
||||
} )
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* istanbul ignore file */
|
||||
const Sentry = require( '@sentry/node' )
|
||||
const { ApolloError } = require( 'apollo-server-express' )
|
||||
|
||||
module.exports = {
|
||||
requestDidStart( ctx ) {
|
||||
return {
|
||||
didResolveOperation( ctx ) {
|
||||
if ( !ctx.operation ) {
|
||||
return
|
||||
}
|
||||
|
||||
let transaction = Sentry.startTransaction( {
|
||||
op: `GQL ${ctx.operation.operation} ${ctx.operation.selectionSet.selections[0].name.value}`,
|
||||
name: `GQL ${ctx.operation.selectionSet.selections[0].name.value}`
|
||||
} )
|
||||
|
||||
Sentry.configureScope( scope => scope.setSpan( transaction ) )
|
||||
ctx.request.transaction = transaction
|
||||
},
|
||||
didEncounterErrors( ctx ) {
|
||||
if ( !ctx.operation )
|
||||
return
|
||||
|
||||
for ( const err of ctx.errors ) {
|
||||
if ( err instanceof ApolloError ) {
|
||||
continue
|
||||
}
|
||||
Sentry.withScope( scope => {
|
||||
scope.setTag( 'kind', ctx.operation.operation )
|
||||
scope.setExtra( 'query', ctx.request.query )
|
||||
scope.setExtra( 'variables', ctx.request.variables )
|
||||
if ( err.path ) {
|
||||
// We can also add the path as breadcrumb
|
||||
scope.addBreadcrumb( {
|
||||
category: "query-path",
|
||||
message: err.path.join( " > " ),
|
||||
level: Sentry.Severity.Debug
|
||||
} )
|
||||
}
|
||||
Sentry.captureException( err )
|
||||
} )
|
||||
}
|
||||
},
|
||||
willSendResponse( ctx ) {
|
||||
if ( ctx.request.transaction ) {
|
||||
ctx.request.transaction.finish( )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* istanbul ignore file */
|
||||
const Sentry = require( '@sentry/node' )
|
||||
const Tracing = require( '@sentry/tracing' )
|
||||
const { machineIdSync } = require( 'node-machine-id' )
|
||||
|
||||
module.exports = function ( app ) {
|
||||
Sentry.setUser( { id: machineIdSync( ) } )
|
||||
|
||||
Sentry.init( {
|
||||
dsn: process.env.SENTRY_DSN || 'https://84171d4d992f43a5bc867a6694934b01@o436188.ingest.sentry.io/5416515',
|
||||
integrations: [
|
||||
new Sentry.Integrations.Http( { tracing: true } ),
|
||||
new Tracing.Integrations.Express( { app } )
|
||||
],
|
||||
tracesSampleRate: 0.5
|
||||
} )
|
||||
|
||||
app.use( Sentry.Handlers.requestHandler( ) )
|
||||
app.use( Sentry.Handlers.tracingHandler( ) )
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
const Sentry = require( '@sentry/node' )
|
||||
|
||||
module.exports = function ( { err, kind, extras } ) {
|
||||
Sentry.withScope( scope => {
|
||||
if ( kind ) scope.setTag( 'kind', kind )
|
||||
if ( extras ) scope.setExtra( 'extras', extras )
|
||||
|
||||
Sentry.captureException( err )
|
||||
} )
|
||||
}
|
||||
@@ -7,6 +7,7 @@ const RedisStore = require( 'connect-redis' )( ExpressSession )
|
||||
const passport = require( 'passport' )
|
||||
const debug = require( 'debug' )
|
||||
|
||||
const sentry = require( `${appRoot}/logging/sentryHelper` )
|
||||
const { getApp, createAuthorizationCode, createAppTokenFromAccessCode, refreshAppToken } = require( './services/apps' )
|
||||
const { createPersonalAccessToken } = require( `${appRoot}/modules/core/services/tokens` )
|
||||
|
||||
@@ -42,7 +43,8 @@ exports.init = ( app, options ) => {
|
||||
let ac = await createAuthorizationCode( { appId: app.id, userId: req.user.id, challenge: req.session.challenge } )
|
||||
return res.redirect( `/auth/finalize?appId=${req.session.appId}&access_code=${ac}` )
|
||||
} catch ( err ) {
|
||||
return res.status( 400 ).send( err.message )
|
||||
sentry( { err } )
|
||||
res.status( 401 ).send( 'Invalid request.' )
|
||||
}
|
||||
} else {
|
||||
if ( process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' ) {
|
||||
@@ -70,7 +72,7 @@ exports.init = ( app, options ) => {
|
||||
let authResponse = await createAppTokenFromAccessCode( { appId: req.body.appId, appSecret: req.body.appSecret, accessCode: req.body.accessCode, challenge: req.body.challenge } )
|
||||
return res.send( authResponse )
|
||||
} catch ( err ) {
|
||||
debug( 'speckle:errors' )( err )
|
||||
sentry( { err } )
|
||||
return res.status( 401 ).send( { err: err.message } )
|
||||
}
|
||||
} )
|
||||
|
||||
@@ -4,7 +4,7 @@ extend type Query {
|
||||
"""
|
||||
All the streams of the current user, pass in the `query` parameter to seach by name, description or ID.
|
||||
"""
|
||||
streams( query: String!, limit: Int! = 25, cursor: String ): StreamCollection
|
||||
streams( query: String, limit: Int = 25, cursor: String ): StreamCollection
|
||||
@hasScope(scope: "streams:read")
|
||||
}
|
||||
|
||||
|
||||
Generated
+1159
-1078
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -26,7 +26,9 @@
|
||||
"author": "The Specklers",
|
||||
"license": "",
|
||||
"dependencies": {
|
||||
"apollo-server-express": "^2.14.2",
|
||||
"@sentry/node": "^5.22.3",
|
||||
"@sentry/tracing": "^5.22.3",
|
||||
"apollo-server-express": "^2.17.0",
|
||||
"apollo-server-testing": "^2.12.0",
|
||||
"app-root-path": "^3.0.0",
|
||||
"auto-load": "^3.0.4",
|
||||
@@ -55,6 +57,7 @@
|
||||
"lodash.values": "^4.3.0",
|
||||
"morgan": "^1.10.0",
|
||||
"morgan-debug": "^2.0.0",
|
||||
"node-machine-id": "^1.1.12",
|
||||
"passport": "^0.4.1",
|
||||
"passport-github2": "^0.1.12",
|
||||
"passport-google-oauth2": "^0.2.0",
|
||||
|
||||
Reference in New Issue
Block a user