This file is indexed.

/usr/share/pyshared/dmedia/gtkui/widgets.py is in dmedia-gtk 0.6.0~repack-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# Authors:
#   Jason Gerard DeRose <jderose@novacut.com>
#   David Green <david4dev@gmail.com>
#
# dmedia: distributed media library
# Copyright (C) 2010 Jason Gerard DeRose <jderose@novacut.com>
#
# This file is part of `dmedia`.
#
# `dmedia` is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# `dmedia` is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with `dmedia`.  If not, see <http://www.gnu.org/licenses/>.

"""
Custom dmedia GTK widgets, currently just `CouchView` and `BrowserMenu`.
"""

from urlparse import urlparse, parse_qsl

from oauth import oauth
from gi.repository import GObject, WebKit, Gtk

from .menu import MENU, ACTIONS
from gettext import gettext as _


class CouchView(WebKit.WebView):
    """
    Transparently sign desktopcouch requests with OAuth.

    desktopcouch uses OAuth to authenticate HTTP requests to CouchDB.  Well,
    technically it can also use basic auth, but if you do this, Stuart Langridge
    will be very cross with you!

    This class wraps a ``gi.repository.WebKit.WebView`` so that you can have a
    single web app that:

        1. Can run in a browser and talk to a remote CouchDB over HTTPS with
           basic auth

        2. Can also run in embedded WebKit and talk to the local desktopcouch
           over HTTP with OAuth

    Being able to do this sort of thing transparently is a big reason why dmedia
    and Novacut are designed the way they are.

    For some background, see:

        https://bugs.launchpad.net/dmedia/+bug/677697

        http://oauth.net/

    Special thanks to Stuart Langridge for the example code that helped get this
    working.
    """

    __gsignals__ = {
        'play': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,
            [GObject.TYPE_PYOBJECT]
        ),
        'open': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,
            [GObject.TYPE_PYOBJECT]
        ),
    }

    def __init__(self, couch_url, oauth_tokens=None):
        super(CouchView, self).__init__()
        self._couch_url = couch_url
        self._couch_netloc = urlparse(couch_url).netloc
        self.connect('resource-request-starting', self._on_resource_request)
        self.connect('navigation-policy-decision-requested',
            self._on_nav_policy_decision
        )
        if oauth_tokens:
            self._oauth = True
            self._consumer = oauth.OAuthConsumer(
                oauth_tokens['consumer_key'],
                oauth_tokens['consumer_secret']
            )
            self._token = oauth.OAuthToken(
                oauth_tokens['token'],
                oauth_tokens['token_secret']
            )
        else:
            self._oauth = False

    def _on_nav_policy_decision(self, view, frame, request, nav, policy):
        """
        Handle user trying to Navigate away from current page.

        Note that this will be called before `CouchView._on_resource_request()`.

        The *policy* arg is a ``WebPolicyDecision`` instance.  To handle the
        decision, call one of:

            * ``WebPolicyDecision.ignore()``
            * ``WebPolicyDecision.use()``
            * ``WebPolicyDecision.download()``

        And then return ``True``.

        Otherwise, return ``False`` or ``None`` to have the WebKit default
        behavior apply.
        """
        uri = request.get_uri()
        u = urlparse(uri)
        if u.netloc == self._couch_netloc and u.scheme in ('http', 'https'):
            return False
        if uri.startswith('play:'):
            self.emit('play', uri)
        elif u.netloc != self._couch_netloc and u.scheme in ('http', 'https'):
            self.emit('open', uri)
        policy.ignore()
        return True

    def _on_resource_request(self, view, frame, resource, request, response):
        """
        When appropriate, OAuth-sign the request prior to it being sent.

        This will only sign requests on the same host and port in the URL passed
        to `CouchView.__init__()`.
        """
        uri = request.get_uri()
        u = urlparse(uri)
        if u.scheme not in ('http', 'https'):  # Ignore data:foo requests
            return
        if u.netloc != self._couch_netloc:  # Dont sign requests to broader net!
            return
        if not self._oauth:  # OAuth info wasn't provided
            return
        query = dict(parse_qsl(u.query))
        # Handle bloody CouchDB having foo.html?dbname URLs, that is
        # a querystring which isn't of the form foo=bar
        if u.query and not query:
            query = {u.query: ''}
        req = oauth.OAuthRequest.from_consumer_and_token(
            self._consumer,
            self._token,
            http_method=request.props.message.props.method,
            http_url=uri,
            parameters=query,
        )
        req.sign_request(
            oauth.OAuthSignatureMethod_HMAC_SHA1(),
            self._consumer,
            self._token
        )
        request.props.message.props.request_headers.append(
            'Authorization', req.to_header()['Authorization']
        )


class BrowserMenu(Gtk.MenuBar):
    """
    The BrowserMenu class creates a menubar for dmedia-gtk, the dmedia
    media browser.

    The menu argument specifies the layout of the menu as a list of menubar
    items. Each item is a dictionary. There are 2 main types of item: action and
    menu.

    Actions are menu items that do something when clicked. The dictionary
    for an action looks like this:
        {
            "label" : "text to display",
            "type" : "action",
            "action" : "action id"
        }
    The label is the text to display (eg. "Close"). The type tells BrowserMenu
    that this item is an action not a menu. The action is a string that is looked
    up in the actions dictionary and refers to a callback function that is executed
    when this menu item is clicked.

    Menus are submenus of the menubar. These can hold other menus and actions.
    The dictionary for a menu looks like this:
        {
            "label" : "text to display",
            "type" : "menu",
            "items" : [item_1, item_2 ... item_n]
        }
    The label is the text to display (eg. "File"). The type tells BrowserMenu
    that this item is a menu not an action. "items" is a list of other items
    that appear in this menu.

    The actions argument is a dictionary of action IDs (strings) and callback
    functions.
        {
            "action1" : lambda *a: ... ,
            "action2" : my_object.method,
            "action3" : some_function
        }

    If menu or actions are not specified the default will be MENU and
    ACTIONS repectively which are defined in menu.py.

    In addition to the main 2 types of menu item, there is a "custom"
    item that allows for any gtk widget to be put in the menu as long
    as gtk itself allows for this.

    The dictionary for a custom item looks like this:
        {
            "type" : "custom",
            "widget" : gtk_widget
        }
    """
    def __init__(self, menu=MENU, actions=ACTIONS):
        super(BrowserMenu, self).__init__()
        self.show()
        self.menu = menu
        self.actions = actions
        self.add_items_to_menu(self, *self.make_menu(self.menu))

    def add_items_to_menu(self, menu, *items):
        for item in items:
            menu.append(item)

    def make_menu(self, menu):
        items = []
        for i in menu:
            if i["type"] == "custom":
                items.append(i["widget"]) #allows for custom widgets, eg. separators
            else:
                item = Gtk.MenuItem()
                item.show()
                item.set_property("use-underline", True) #allow keyboard nav
                item.set_label(_(i["label"]))
                if i["type"] == "menu":
                    submenu = Gtk.Menu()
                    submenu.show()
                    self.add_items_to_menu(submenu, *self.make_menu(i["items"]))
                    item.set_submenu(submenu)
                elif i["type"] == "action":
                    item.connect("activate", self.actions[i["action"]])
                items.append(item)
        return items