1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

# Copyright 2014 The Distro Tracker Developers 

# See the COPYRIGHT file at the top-level directory of this distribution and 

# at https://deb.li/DTAuthors 

# 

# This file is part of Distro Tracker. It is subject to the license terms 

# in the LICENSE file found in the top-level directory of this 

# distribution and at https://deb.li/DTLicense. No part of Distro Tracker, 

# including this file, may be copied, modified, propagated, or distributed 

# except according to the terms contained in the LICENSE file. 

 

""" 

Module including some utility functions to inject links in plain text. 

""" 

import re 

 

from django.conf import settings 

 

from distro_tracker.core.utils.plugins import PluginRegistry 

 

 

class Linkify(metaclass=PluginRegistry): 

""" 

A base class representing ways to inject useful links in plain text data 

 

If you want to recognize a new syntax where links could provide value to 

a view of the content, just create a subclass and implement the linkify 

method. 

""" 

 

@staticmethod 

def linkify(text): 

""" 

:param text: the text where we should inject HTML links 

:type param: str 

:returns: the text formatted with HTML links 

:rtype: str 

""" 

return text 

 

 

class LinkifyHttpLinks(Linkify): 

""" 

Detect http:// and https:// URLs and transform them in true HTML 

links. 

""" 

 

@staticmethod 

def linkify(text): 

return re.sub(r'(?:^|(?<=\s))(https?://[^\s]*)', 

r'<a href="\1">\1</a>', 

text) 

 

 

class LinkifyDebianBugLinks(Linkify): 

""" 

Detect "Closes: #123, 234" syntax used in Debian changelogs to close 

bugs and inject HTML links to the corresponding bug tracker entry. 

Also handles the "Closes: 123 456" fields of .changes files. 

""" 

 

close_prefix = 'Closes:' 

close_field = 'Closes:' 

bug_url = 'https://bugs.debian.org/' 

 

@classmethod 

def _linkify_field(cls, text): 

67 ↛ 68line 67 didn't jump to line 68, because the condition on line 67 was never true if not cls.close_field: 

return text 

split_text = re.split( 

'(^' + cls.close_field + r'(?: \d+)+\s*$)', 

text, flags=re.IGNORECASE | re.MULTILINE) 

generated_link = '' 

for i, txt in enumerate(split_text): 

if i % 2: 

new_txt = re.sub( 

r'(\d+)', r'<a href="{}\1">\1</a>'.format(cls.bug_url), 

txt, flags=re.IGNORECASE) 

generated_link += new_txt 

else: 

generated_link += txt 

return generated_link 

 

@classmethod 

def _linkify_changelog_entry(cls, text): 

split_text = re.split( 

'(' + cls.close_prefix + 

r'\s*(?:bug)?(?:#)?\d+(?:\s*,\s*(?:bug)?(?:#)?\d+)*)', 

text, flags=re.IGNORECASE) 

generated_link = '' 

for i, txt in enumerate(split_text): 

if i % 2: 

new_txt = re.sub( 

r'((?:#)?(\d+))', 

r'<a href="{}\2">\1</a>'.format(cls.bug_url), 

txt, flags=re.IGNORECASE) 

generated_link += new_txt 

else: 

generated_link += txt 

return generated_link 

 

@classmethod 

def linkify(cls, text): 

return cls._linkify_changelog_entry(cls._linkify_field(text)) 

 

 

class LinkifyUbuntuBugLinks(LinkifyDebianBugLinks): 

""" 

Detect "LP: #123, 234" syntax used in Ubuntu changelogs to close 

bugs and inject HTML links to the corresponding bug tracker entry. 

""" 

 

close_prefix = 'LP:' 

close_field = 'Launchpad-Bugs-Fixed:' 

bug_url = 'https://bugs.launchpad.net/bugs/' 

 

 

class LinkifyCVELinks(Linkify): 

""" 

Detect "CVE-2014-1234" words and transform them into links to the 

CVE tracker at cve.mitre.org. The exact URL can be overridden with a 

``DISTRO_TRACKER_CVE_URL`` configuration setting to redirect 

the URL to a custom tracker. 

""" 

 

@staticmethod 

def linkify(text): 

address = getattr(settings, 'DISTRO_TRACKER_CVE_URL', 

'https://cve.mitre.org/cgi-bin/cvename.cgi?name=') 

return re.sub(r'(?:(?<=\s|\()|\A)((CVE)-(\d{4})-(\d{4,}))', 

r'<a href="{}\1">\1</a>'.format(address), 

text, flags=re.IGNORECASE) 

 

 

def linkify(message): 

""" 

:param message: the message where we should inject HTML links 

:type param: str 

:returns: the message formatted with HTML links 

:rtype: str 

""" 

for plugin in Linkify.plugins: 

message = plugin.linkify(message) 

return message