or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

autolink.mdclick-handling.mdindex.mdlink-commands.mdlink-configuration.mdpaste-processing.mdurl-validation.md

url-validation.mddocs/

0

# URL Validation and Security

1

2

XSS protection utilities and URI validation for secure link handling. The validation system prevents malicious URLs while allowing legitimate protocols and custom validation logic.

3

4

## Capabilities

5

6

### URI Validation Function

7

8

Core URL validation function that checks if a URI is allowed based on protocol whitelist and validation rules.

9

10

```typescript { .api }

11

/**

12

* Validates if a URI is allowed based on protocol whitelist

13

* @param uri - URI to validate (can be undefined)

14

* @param protocols - Optional array of custom protocols to allow

15

* @returns True if URI is allowed, false otherwise

16

*/

17

function isAllowedUri(

18

uri: string | undefined,

19

protocols?: LinkOptions['protocols']

20

): boolean;

21

```

22

23

**Usage Examples:**

24

25

```typescript

26

import { isAllowedUri } from "@tiptap/extension-link";

27

28

// Basic validation

29

const isValid = isAllowedUri('https://example.com'); // true

30

const isValid2 = isAllowedUri('javascript:alert("xss")'); // false

31

32

// Custom protocols

33

const customProtocols = ['ftp', 'ssh', { scheme: 'git', optionalSlashes: true }];

34

const isValid3 = isAllowedUri('ftp://files.example.com', customProtocols); // true

35

const isValid4 = isAllowedUri('git:github.com/user/repo', customProtocols); // true

36

37

// Undefined/null handling

38

const isValid5 = isAllowedUri(undefined); // true (allows empty/null URIs)

39

const isValid6 = isAllowedUri(''); // true

40

```

41

42

### Default Allowed Protocols

43

44

The validation system includes a comprehensive list of safe protocols by default.

45

46

```typescript { .api }

47

/**

48

* Default allowed protocols for URI validation

49

*/

50

const allowedProtocols: string[] = [

51

'http',

52

'https',

53

'ftp',

54

'ftps',

55

'mailto',

56

'tel',

57

'callto',

58

'sms',

59

'cid',

60

'xmpp'

61

];

62

```

63

64

### Paste Detection Regex

65

66

Regular expression for detecting URLs in pasted content.

67

68

```typescript { .api }

69

/**

70

* Regular expression for detecting URLs in pasted content

71

* Matches http/https URLs with proper domain and path structure

72

*/

73

const pasteRegex: RegExp;

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

import { pasteRegex } from "@tiptap/extension-link";

80

81

// Test if pasted content is a URL

82

const pastedText = 'https://tiptap.dev/docs';

83

const isUrl = pasteRegex.test(pastedText); // true

84

85

// Extract URLs from text

86

const text = 'Visit https://tiptap.dev and https://example.com for more info';

87

const urls = text.match(pasteRegex);

88

// ['https://tiptap.dev', 'https://example.com']

89

```

90

91

### Validation Context Interface

92

93

Context object provided to custom validation functions with helper utilities and configuration.

94

95

```typescript { .api }

96

interface ValidationContext {

97

/**

98

* The default validation function

99

* @param url - URL to validate

100

* @returns True if URL passes default validation

101

*/

102

defaultValidate: (url: string) => boolean;

103

104

/**

105

* Array of allowed protocols for the URL (e.g., "http", "https")

106

* As defined in the protocols option

107

*/

108

protocols: Array<LinkProtocolOptions | string>;

109

110

/**

111

* Default protocol (e.g., 'http')

112

* As defined in the defaultProtocol option

113

*/

114

defaultProtocol: string;

115

}

116

```

117

118

**Usage Examples:**

119

120

```typescript

121

import { Editor } from "@tiptap/core";

122

import { Link } from "@tiptap/extension-link";

123

124

const editor = new Editor({

125

extensions: [

126

Link.configure({

127

isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {

128

// Allow relative URLs

129

if (url.startsWith('./') || url.startsWith('../')) {

130

return true;

131

}

132

133

// Allow localhost in development

134

if (process.env.NODE_ENV === 'development' && url.includes('localhost')) {

135

return true;

136

}

137

138

// Use default validation for everything else

139

return defaultValidate(url);

140

},

141

}),

142

],

143

});

144

```

145

146

### Custom Validation Functions

147

148

Advanced validation configurations for specific security requirements.

149

150

**Security-First Validation:**

151

152

```typescript

153

import { Editor } from "@tiptap/core";

154

import { Link } from "@tiptap/extension-link";

155

156

const editor = new Editor({

157

extensions: [

158

Link.configure({

159

isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {

160

// Strict security: only allow specific domains

161

const allowedDomains = ['example.com', 'trusted-site.org'];

162

163

try {

164

const urlObj = new URL(url);

165

return allowedDomains.includes(urlObj.hostname);

166

} catch {

167

return false; // Invalid URLs are rejected

168

}

169

},

170

shouldAutoLink: (url) => {

171

// Don't auto-link internal URLs

172

return !url.includes('internal.company.com');

173

},

174

}),

175

],

176

});

177

```

178

179

**Development-Friendly Validation:**

180

181

```typescript

182

const editor = new Editor({

183

extensions: [

184

Link.configure({

185

isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {

186

// Development: allow localhost and file protocols

187

if (process.env.NODE_ENV === 'development') {

188

if (url.startsWith('file://') || url.includes('localhost') || url.includes('127.0.0.1')) {

189

return true;

190

}

191

}

192

193

// Production: use strict validation

194

return defaultValidate(url);

195

},

196

}),

197

],

198

});

199

```

200

201

### Protocol Registration

202

203

The validation system works with linkifyjs protocol registration for custom schemes.

204

205

**Usage Examples:**

206

207

```typescript

208

import { Editor } from "@tiptap/core";

209

import { Link } from "@tiptap/extension-link";

210

211

const editor = new Editor({

212

extensions: [

213

Link.configure({

214

protocols: [

215

'ftp',

216

'ssh',

217

{ scheme: 'git', optionalSlashes: true },

218

{ scheme: 'vscode', optionalSlashes: false },

219

],

220

isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {

221

// Custom validation for registered protocols

222

if (url.startsWith('vscode://')) {

223

// Only allow specific VSCode extension URLs

224

return url.includes('vscode://extension/');

225

}

226

227

return defaultValidate(url);

228

},

229

}),

230

],

231

});

232

```

233

234

### Whitespace Handling

235

236

Unicode whitespace utilities for robust URL processing and validation.

237

238

```typescript { .api }

239

/** Unicode whitespace pattern from DOMPurify */

240

const UNICODE_WHITESPACE_PATTERN: string;

241

242

/** RegExp for matching Unicode whitespace */

243

const UNICODE_WHITESPACE_REGEX: RegExp;

244

245

/** RegExp for matching whitespace at end of string */

246

const UNICODE_WHITESPACE_REGEX_END: RegExp;

247

248

/** Global RegExp for replacing Unicode whitespace */

249

const UNICODE_WHITESPACE_REGEX_GLOBAL: RegExp;

250

```

251

252

**Usage Examples:**

253

254

```typescript

255

import {

256

UNICODE_WHITESPACE_REGEX_GLOBAL

257

} from "@tiptap/extension-link";

258

259

// Clean URL before validation

260

function cleanUrl(url: string): string {

261

return url.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '');

262

}

263

264

const cleanedUrl = cleanUrl('https://example.com\u00A0\u2000'); // 'https://example.com'

265

```

266

267

### XSS Prevention

268

269

The validation system specifically prevents common XSS attack vectors.

270

271

**Blocked Patterns:**

272

273

```typescript

274

// These URLs are automatically blocked by default validation:

275

// - javascript: protocol

276

// - data: protocol with executable content

277

// - vbscript: protocol

278

// - about: protocol (except about:blank)

279

// - file: protocol (in most configurations)

280

281

const maliciousUrls = [

282

'javascript:alert("xss")',

283

'data:text/html,<script>alert("xss")</script>',

284

'vbscript:alert("xss")',

285

];

286

287

maliciousUrls.forEach(url => {

288

const isAllowed = isAllowedUri(url); // false for all

289

});

290

```

291

292

## Types

293

294

```typescript { .api }

295

/** Link protocol options for custom scheme registration */

296

interface LinkProtocolOptions {

297

scheme: string;

298

optionalSlashes?: boolean;

299

}

300

301

/** Validation context provided to custom validation functions */

302

interface ValidationContext {

303

defaultValidate: (url: string) => boolean;

304

protocols: Array<LinkProtocolOptions | string>;

305

defaultProtocol: string;

306

}

307

```