u-wave-announce 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,28 +5,22 @@ server listing at https://hub.u-wave.net.
5
5
 
6
6
  ## Usage
7
7
 
8
+ The announce plugin is added by default if you use the executable provided
9
+ with üWave Core. If you are using the üWave Core Node.js API, install and
10
+ add it manually:
11
+
8
12
  ```bash
9
- npm install --save u-wave-announce
13
+ npm install u-wave-announce
10
14
  ```
11
15
 
12
16
  ```js
13
17
  import announce from 'u-wave-announce';
14
18
 
15
- uw.use(announce({
16
- name: 'Your server name',
17
- subtitle: 'Very short description', // Up to about 30 characters.
18
- description: `
19
- Longer description about your server, perhaps with a list of rules.
20
- May include _markdown_, even!
21
- `,
22
- url: 'https://my-uwave-server.com',
23
- }));
19
+ uw.use(announce);
24
20
  ```
25
21
 
26
- By default, the plugin sends announce messages to the announce server behind
27
- https://hub.u-wave.net, namely https://announce.u-wave.net.
28
-
29
- ## Options
22
+ ## Runtime Options
23
+ This plugin can be configured at runtime using the admin panel.
30
24
 
31
25
  ### `name` (required)
32
26
 
@@ -51,18 +45,6 @@ including images and links. This can be a good place to put rules, links to
51
45
  social media accounts associated with your server, and whatever else you want
52
46
  visitors to know.
53
47
 
54
- Indentation is stripped from this option, so template strings can be used like:
55
-
56
- ```js
57
- announce({
58
- description: `
59
- # My Awesome Server
60
-
61
- We play cool stuff, and cool stuff only!
62
- `
63
- });
64
- ```
65
-
66
48
  ### `hub`
67
49
 
68
50
  The announce server to announce to. Uses https://announce.u-wave.net, the server
package/package.json CHANGED
@@ -1,13 +1,11 @@
1
1
  {
2
2
  "name": "u-wave-announce",
3
3
  "description": "Announce your üWave server's existence to the world.",
4
- "version": "0.5.0",
4
+ "version": "0.5.3",
5
5
  "author": "Renée Kooi <renee@kooi.me>",
6
6
  "dependencies": {
7
- "debug": "^4.0.0",
8
- "find-cache-dir": "^3.0.0",
7
+ "debug": "^4.3.2",
9
8
  "libsodium-wrappers": "^0.7.8",
10
- "ms": "^2.0.0",
11
9
  "node-fetch": "^2.6.0",
12
10
  "strip-indent": "^3.0.0"
13
11
  },
@@ -19,5 +17,8 @@
19
17
  "repository": {
20
18
  "git": "https://github.com/u-wave/hub.git",
21
19
  "directory": "plugin"
20
+ },
21
+ "scripts": {
22
+ "test": "node test"
22
23
  }
23
24
  }
package/src/plugin.js CHANGED
@@ -1,12 +1,23 @@
1
- const fs = require('fs').promises;
1
+ 'use strict';
2
+
3
+ const { promisify } = require('util');
4
+ const randomBytes = promisify(require('crypto').randomBytes);
2
5
  const fetch = require('node-fetch');
3
- const ms = require('ms');
4
6
  const stripIndent = require('strip-indent');
5
- const findCacheDir = require('find-cache-dir');
6
7
  const debug = require('debug')('uwave:announce');
7
8
  const sodium = require('./signatures');
8
9
  const pkg = require('../package.json');
9
10
 
11
+ /**
12
+ * Fallback logger implementation for üWave Core versions that do
13
+ * not come with a logger yet.
14
+ */
15
+ const debugLogger = {
16
+ debug,
17
+ info: debug,
18
+ error: debug,
19
+ };
20
+
10
21
  const optionsSchema = {
11
22
  type: 'object',
12
23
  title: 'Announce',
@@ -19,6 +30,14 @@ const optionsSchema = {
19
30
  description: 'Whether to announce at all.',
20
31
  default: false,
21
32
  },
33
+ seed: {
34
+ type: 'string',
35
+ pattern: /^[0-9a-f]{64}$/.source,
36
+ // Should not be edited by users.
37
+ readOnly: true,
38
+ // Should not be exposed to users.
39
+ writeOnly: true,
40
+ },
22
41
  name: {
23
42
  type: 'string',
24
43
  title: 'Server Name',
@@ -81,36 +100,6 @@ function stripSlashes(url) {
81
100
  return url.replace(/\/+$/, '');
82
101
  }
83
102
 
84
- async function getKeyPair(seed) {
85
- const keyPairPath = findCacheDir({
86
- name: pkg.name,
87
- create: true,
88
- thunk: true,
89
- })('keypair.json');
90
- try {
91
- const { publicKey, secretKey, forSeed } = JSON.parse(
92
- await fs.readFile(keyPairPath, 'utf8'),
93
- );
94
-
95
- if (Buffer.compare(Buffer.from(forSeed), Buffer.from(seed)) !== 0) {
96
- throw new Error('this error object is unused');
97
- }
98
-
99
- return {
100
- publicKey: Buffer.from(publicKey, 'base64'),
101
- secretKey: Buffer.from(secretKey, 'base64'),
102
- };
103
- } catch (error) {
104
- const { publicKey, secretKey } = await sodium.keyPair(seed);
105
- await fs.writeFile(keyPairPath, JSON.stringify({
106
- publicKey: publicKey.toString('base64'),
107
- secretKey: secretKey.toString('base64'),
108
- forSeed: seed,
109
- }, null, 2), 'utf8');
110
- return { publicKey, secretKey };
111
- }
112
- }
113
-
114
103
  async function getAnnounceData(uw, options) {
115
104
  const url = stripSlashes(options.url);
116
105
 
@@ -118,8 +107,12 @@ async function getAnnounceData(uw, options) {
118
107
  // the relationships.
119
108
  const entry = await uw.booth.getCurrentEntry();
120
109
  if (entry) {
121
- entry.populate('user media.media');
122
- await entry.execPopulate();
110
+ if (entry.execPopulate) {
111
+ entry.populate('user media.media');
112
+ await entry.execPopulate();
113
+ } else {
114
+ await entry.populate('user media.media');
115
+ }
123
116
  }
124
117
 
125
118
  // TODO add something to üWave Core so we don't have to manually ask Redis for
@@ -158,25 +151,43 @@ async function getAnnounceData(uw, options) {
158
151
  };
159
152
  }
160
153
 
161
- async function announcePlugin(uw, staticOptions) {
162
- const { publicKey, secretKey } = await getKeyPair(staticOptions.seed);
154
+ async function getOrGenerateSeed(uw) {
155
+ const options = await uw.config.get(optionsSchema['uw:key']);
156
+ if (!options.seed) {
157
+ options.seed = (await randomBytes(32)).toString('hex');
158
+ await uw.config.set(optionsSchema['uw:key'], options);
159
+ }
160
+ return Buffer.from(options.seed, 'hex');
161
+ }
163
162
 
163
+ async function announcePlugin(uw, staticOptions) {
164
164
  uw.config.register(optionsSchema['uw:key'], optionsSchema);
165
165
 
166
+ // üWave Core 0.5.0 and up have a `pino` logger
167
+ const logger = uw.logger
168
+ ? uw.logger.child({ ns: 'uwave:announce' })
169
+ : debugLogger;
170
+
171
+ const seed = staticOptions.seed || await getOrGenerateSeed(uw);
172
+ // This takes up to a few 100 ms but it is a one-time startup cost…
173
+ // Maybe it makes sense to cache this, or to not block the rest of
174
+ // the startup work. For now, we just do the easy thing.
175
+ const { publicKey, secretKey } = await sodium.keyPair(seed);
176
+
166
177
  async function announce() {
167
178
  const options = await uw.config.get(optionsSchema['uw:key']);
168
179
  if (typeof options !== 'object') {
169
- debug('announcing not configured, skipping');
180
+ logger.debug('announcing not configured, skipping');
170
181
  return;
171
182
  }
172
183
  if (!options.enabled) {
173
- debug('announcing disabled, skipping');
184
+ logger.debug('announcing disabled, skipping');
174
185
  return;
175
186
  }
176
187
 
177
188
  const hubHost = options.hub || 'https://announce.u-wave.net';
178
189
  const announceUrl = `${stripSlashes(hubHost)}/announce/${Buffer.from(publicKey).toString('hex')}`;
179
- debug('announcing to', announceUrl);
190
+ logger.info('announcing to', announceUrl);
180
191
 
181
192
  const announcement = await getAnnounceData(uw, options);
182
193
  const data = JSON.stringify(announcement);
@@ -185,6 +196,7 @@ async function announcePlugin(uw, staticOptions) {
185
196
  await fetch(announceUrl, {
186
197
  method: 'post',
187
198
  headers: {
199
+ 'user-agent': `u-wave-announce ${pkg.version}`,
188
200
  'content-type': 'application/json',
189
201
  },
190
202
  body: JSON.stringify({
@@ -194,8 +206,8 @@ async function announcePlugin(uw, staticOptions) {
194
206
  });
195
207
  }
196
208
 
197
- function onError(err) {
198
- debug(err);
209
+ function onError(error) {
210
+ logger.error({ err: error });
199
211
  }
200
212
 
201
213
  let interval;
@@ -208,7 +220,7 @@ async function announcePlugin(uw, staticOptions) {
208
220
  // we're still alive.
209
221
  interval = setInterval(() => {
210
222
  announce().catch(onError);
211
- }, ms('1 minute'));
223
+ }, 60_000);
212
224
  });
213
225
 
214
226
  // Announce again every time the song changes.
package/src/signatures.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  // Based on https://github.com/mafintosh/sodium-signatures/blob/master/index.js
2
4
  const sodium = require('libsodium-wrappers');
3
5
 
package/test.js ADDED
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+
5
+ assert.doesNotThrow(() => {
6
+ // Just to make sure it does not crash :)
7
+ // eslint-disable-next-line global-require
8
+ require('./src/plugin');
9
+ });