fixing merge conflits

This commit is contained in:
Chris Troutner
2026-02-02 18:39:57 -07:00
34 changed files with 824 additions and 917 deletions
+26 -58
View File
@@ -51,70 +51,37 @@ class Admin {
// used by the Listing Manager and test scripts, in order access private API
// functions.
async createSystemUser () {
// Create the system user.
try {
context.password = _this._randomString(20)
const options = {
method: 'POST',
url: `${LOCALHOST}/users`,
data: {
user: {
email: 'system@system.com',
password: context.password,
name: 'admin'
}
}
const context = {
email: 'system@system.com',
name: 'admin',
password: _this.config.adminPassword || _this._randomString(20),
type: 'admin'
}
const result = await _this.axios.request(options)
// console.log('admin.data: ', result.data)
// Check if the user already exists
let adminUser = await _this.User.findOne({ email: context.email })
context.email = result.data.user.email
context.id = result.data.user._id
context.token = result.data.token
if (adminUser) {
// Update the password
adminUser.password = context.password
} else {
// Create a new admin user
adminUser = new _this.User(context)
}
// Update context with the new user id and token
context.id = adminUser._id
context.token = await adminUser.generateToken()
// Get the mongoDB entry
const user = await _this.User.findById(context.id)
// Save the user
await adminUser.save()
// Change the user type to admin
user.type = 'admin'
// console.log(`user created: ${JSON.stringify(user, null, 2)}`)
// Save the user model.
await user.save()
// console.log(`admin user created: ${JSON.stringify(result.body, null, 2)}`)
// console.log(`with password: ${context.password}`)
// Write out the system user information to a JSON file that external
// applications like the Task Manager and the test scripts can access.
await jsonFiles.writeJSON(context, JSON_PATH)
// console.log('context: ', context)
// console.log('JSON_PATH: ', JSON_PATH)
// Write the user data to the JSON file
await _this.jsonFiles.writeJSON(context, JSON_PATH)
return context
} catch (err) {
// Handle existing system user.
if (err.response.status === 422) {
try {
// Delete the existing user
await _this.deleteExistingSystemUser()
// Call this function again.
return _this.createSystemUser()
} catch (err2) {
console.error(
'Error in admin.js/createSystemUser() while trying generate new system user.'
)
// process.end(1)
throw err2
}
} else {
console.log('Error in admin.js/createSystemUser: ')
// process.end(1)
throw err
}
} catch (error) {
console.log('Error in admin.js/createSystemUser()')
throw error
}
}
@@ -129,6 +96,7 @@ class Admin {
})
await _this.User.deleteOne({ email: 'system@system.com' })
return true
} catch (err) {
console.log('Error in admin.js/deleteExistingSystemUser()')
throw err
@@ -152,7 +120,7 @@ class Admin {
Accept: 'application/json'
},
data: {
email: 'system@system.com',
email: existingUser.email,
password: existingUser.password
}
}
+2
View File
@@ -4,11 +4,13 @@
// Load Mongoose models.
import Users from './models/users.js'
import Usage from './models/usage.js'
class LocalDB {
constructor () {
// Encapsulate dependencies
this.Users = Users
this.Usage = Usage
}
}
+15
View File
@@ -0,0 +1,15 @@
/*
Usage data model
*/
// Global npm libraries
import mongoose from 'mongoose'
const Usage = new mongoose.Schema({
ip: { type: String },
url: { type: String },
method: { type: String },
timestamp: { type: Date }
})
export default mongoose.model('usage', Usage)
+7
View File
@@ -20,6 +20,13 @@ class Wallet {
// Bind 'this' object to all subfunctions
this.instanceWalletWithoutInitialization = this.instanceWalletWithoutInitialization.bind(this)
this._instanceWallet = this._instanceWallet.bind(this)
this.openWallet = this.openWallet.bind(this)
this.instanceWallet = this.instanceWallet.bind(this)
this.incrementNextAddress = this.incrementNextAddress.bind(this)
this.getKeyPair = this.getKeyPair.bind(this)
this.optimize = this.optimize.bind(this)
this.getBalance = this.getBalance.bind(this)
}
// This is used for initializing the wallet, without waiting to update the wallet
+56 -1
View File
@@ -58,7 +58,26 @@ class IpfsRESTControllerLib {
}
}
// Return information on IPFS peers this node is connected to.
/**
* @api {post} /ipfs/peers Get information on IPFS peers this node is connected to
* @apiPermission public
* @apiName GetIpfsPeers
* @apiGroup REST IPFS
*
* @apiParam {Boolean} [showAll=false] Whether to include detailed peer data
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/peers \
* -d '{"showAll": false}'
*
* @apiSuccess {Object[]} peers Array of peer objects
* @apiSuccess {String} peers[].peer Peer ID
* @apiSuccess {String} peers[].name Peer name
* @apiSuccess {String} peers[].protocol Protocol used by the peer
* @apiSuccess {String} peers[].version Peer version
* @apiSuccess {String} peers[].connectionAddr Connection address
* @apiSuccess {Object} [peers[].peerData] Detailed peer data (when showAll=true)
*/
async getPeers (ctx) {
try {
const showAll = ctx.request.body.showAll
@@ -73,6 +92,24 @@ class IpfsRESTControllerLib {
}
}
/**
* @api {post} /ipfs/relays Get data about the known Circuit Relays
* @apiPermission public
* @apiName GetIpfsRelays
* @apiGroup REST IPFS
*
* @apiDescription Returns information about Circuit Relays, both v1 and v2, that this node knows about. V2 relays are hydrated with peer data from the connected peers list.
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/relays
*
* @apiSuccess {Object} relays Object containing relay information
* @apiSuccess {Object[]} relays.v2Relays Array of v2 Circuit Relay objects
* @apiSuccess {String} relays.v2Relays[].ipfsId IPFS ID of the relay
* @apiSuccess {String} relays.v2Relays[].name Name of the relay (hydrated from peer data)
* @apiSuccess {String} relays.v2Relays[].description Description of the relay (hydrated from peer data)
* @apiSuccess {Object[]} relays.v1Relays Array of v1 Circuit Relay configurations
*/
// Get data about the known Circuit Relays. Hydrate with data from peers list.
async getRelays (ctx) {
try {
@@ -86,6 +123,24 @@ class IpfsRESTControllerLib {
}
}
/**
* @api {post} /ipfs/connect Connect to a specific IPFS peer
* @apiPermission public
* @apiName ConnectToIpfsPeer
* @apiGroup REST IPFS
*
* @apiDescription Attempts to establish a connection to a specific IPFS peer using the provided multiaddr. Optionally returns detailed information about the connection.
*
* @apiParam {String} multiaddr Multiaddress of the peer to connect to (required)
* @apiParam {Boolean} [getDetails=false] Whether to return detailed connection information
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/connect \
* -d '{"multiaddr": "/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu", "getDetails": false}'
*
* @apiSuccess {Boolean} success Indicates whether the connection attempt was successful
* @apiSuccess {Object} [details] Additional connection details (when getDetails=true)
*/
async connect (ctx) {
try {
const multiaddr = ctx.request.body.multiaddr
+12 -1
View File
@@ -10,6 +10,8 @@ import UserRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
import config from '../../../../config/index.js'
let _this
class UserRouter {
@@ -34,6 +36,7 @@ class UserRouter {
}
// Encapsulate dependencies.
this.config = config
this.userRESTController = new UserRESTControllerLib(dependencies)
this.validators = new Validators()
@@ -52,7 +55,7 @@ class UserRouter {
}
// Define the routes and attach the controller.
this.router.post('/', this.userRESTController.createUser)
this.router.post('/', this.createUser)
this.router.get('/', this.getAll)
this.router.get('/:id', this.getById)
this.router.put('/:id', this.updateUser)
@@ -63,6 +66,14 @@ class UserRouter {
app.use(this.router.allowedMethods())
}
async createUser (ctx, next) {
if (process.env.DISABLE_NEW_ACCOUNTS) {
await _this.validators.ensureAdmin(ctx, next)
}
await _this.userRESTController.createUser(ctx, next)
return true
}
async getAll (ctx, next) {
await _this.validators.ensureUser(ctx, next)
await _this.userRESTController.getUsers(ctx, next)
+38 -17
View File
@@ -1,6 +1,6 @@
/*
This Controller library is concerned with timer-based functions that are
kicked off periodicially.
kicked off periodically.
*/
import config from '../../config/index.js'
@@ -23,55 +23,76 @@ class TimerControllers {
this.debugLevel = localConfig.debugLevel
// Constants
this.cleanUsageInterval = 60000 * 60 // 1 hour
this.backupUsageInterval = 60000 * 10 // 10 minutes
// Encapsulate dependencies
this.config = config
// Bind 'this' object to all subfunctions.
this.exampleTimerFunc = this.exampleTimerFunc.bind(this)
this.cleanUsage = this.cleanUsage.bind(this)
// this.startTimers()
this.backupUsage = this.backupUsage.bind(this)
}
// Start all the time-based controllers.
startTimers () {
// Any new timer control functions can be added here. They will be started
// when the server starts.
this.optimizeWalletHandle = setInterval(this.exampleTimerFunc, 60000 * 60)
this.cleanUsageHandle = setInterval(this.cleanUsage, 60000 * 60) // 1 hour
this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval)
this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval)
return true
}
stopTimers () {
clearInterval(this.optimizeWalletHandle)
clearInterval(this.cleanusageHandle)
clearInterval(this.cleanUsageHandle)
clearInterval(this.backupUsageHandle)
}
// Replace this example function with your own timer handler.
exampleTimerFunc (negativeTest) {
// Clean the usage state so that stats reflect the last 24 hours.
cleanUsage () {
try {
console.log('Example timer controller executed.')
clearInterval(this.cleanUsageHandle)
if (negativeTest) throw new Error('test error')
const now = new Date()
console.log(`cleanUsage() Timer Controller executing at ${now.toLocaleString()}`)
this.useCases.usage.cleanUsage()
this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval)
return true
} catch (err) {
console.error('Error in exampleTimerFunc(): ', err)
console.error('Error in time-controller.js/cleanUsage(): ', err)
this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval)
// Note: Do not throw an error. This is a top-level function.
return false
}
}
// Clean the usage state so that stats reflect the last 24 hours.
cleanUsage () {
// Backup the usage stats to the database
async backupUsage () {
try {
this.useCases.usage.cleanUsage()
clearInterval(this.backupUsageHandle)
console.log('backupUsage() Timer Controller executing at ', new Date().toLocaleString())
// Clear the database of old usage data.
await this.useCases.usage.clearUsage()
// Save the current usage snapshot to the database.
await this.useCases.usage.saveUsage()
this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval)
return true
} catch (err) {
console.error('Error in time-controller.js/cleanUsage(): ', err)
console.error('Error in time-controller.js/backupUsage(): ', err)
this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval)
// Note: Do not throw an error. This is a top-level function.
return false
+3
View File
@@ -26,6 +26,9 @@ class UseCases {
// Run any startup Use Cases at the start of the app.
async start () {
// Load the usage stats from the database
await this.usage.loadUsage()
console.log('Async Use Cases have been started.')
return true
+78
View File
@@ -3,6 +3,10 @@
for tracking the usage of REST API and JSON RPC calls. This library is used
by admins to keep an eye on how many API calls were made in a 24-hour and
1-hour time period.
Usage stats are held in memory. But they are periodically backed up to the
Mongo database. On startup, the usage stats are loaded from the database.
This allows the usage stats to be persisted across restarts.
*/
// This global variable is used to share data between the REST middleware and
@@ -19,11 +23,17 @@ class UsageUseCases {
)
}
// Encapsulate dependencies
this.UsageModel = this.adapters.localdb.Usage
// Bind 'this' object to all subfunctions
this.cleanUsage = this.cleanUsage.bind(this)
this.getRestSummary = this.getRestSummary.bind(this)
this.getTopIps = this.getTopIps.bind(this)
this.getTopEndpoints = this.getTopEndpoints.bind(this)
this.clearUsage = this.clearUsage.bind(this)
this.saveUsage = this.saveUsage.bind(this)
this.loadUsage = this.loadUsage.bind(this)
// State
}
@@ -36,7 +46,11 @@ class UsageUseCases {
const now = new Date()
const twentyFourHoursAgo = now.getTime() - (60000 * 60 * 24)
console.log('cleanUsage() now: ', now)
console.log('cleanUsage() restCalls.length before filtering: ', restCalls.length)
restCalls = restCalls.filter(x => x.timestamp > twentyFourHoursAgo)
console.log('cleanUsage() restCalls.length after filtering: ', restCalls.length)
return restCalls
} catch (err) {
console.error('Error in usage-use-cases.js/cleanUsage()')
@@ -104,6 +118,70 @@ class UsageUseCases {
throw err
}
}
// Clear the usage database data
async clearUsage () {
try {
await this.UsageModel.deleteMany({})
// Debugging: verify the database is empty
// Delete this code after debugging
const usage = await this.UsageModel.find({})
console.log('clearUsage() usage: ', usage)
return true
} catch (err) {
console.error('Error in usage-use-cases.js/clearUsage()')
throw err
}
}
// Save the usage data to the database
async saveUsage (inObj = {}) {
try {
for (let i = 0; i < restCalls.length; i++) {
const thisRestCall = restCalls[i]
// Debugging: delete this code after debugging
// if (i === 5) {
// console.log('saveUsage() thisRestCall: ', thisRestCall)
// }
const usageData = {
ip: thisRestCall.ip,
url: thisRestCall.url,
method: thisRestCall.method,
timestamp: thisRestCall.timestamp
}
const usage = new this.UsageModel(usageData)
await usage.save()
}
return true
} catch (err) {
console.error('Error in usage-use-cases.js/saveUsage()')
throw err
}
}
// Load usage data from the database
async loadUsage () {
try {
const usage = await this.UsageModel.find({})
// console.log('usage: ', usage)
// Debugging: delete this code after debugging
if (usage[5]) {
console.log('loadUsage() usage[5]: ', usage[5])
}
restCalls = usage
return usage
} catch (err) {
console.error('Error in usage-use-cases.js/loadUsage(): ', err)
return false
// throw err
}
}
}
// This Koa middleware is called any time there is a REST API. It logs the