Mercurial > prosody-modules
annotate mod_sasl2_bind2/mod_sasl2_bind2.lua @ 5039:c0d243b27e64
mod_sasl2, mod_sasl_bind2, mod_sasl2_sm: Bump XEP-0388 namespace
This is the namespace for the proposed update to XEP-0388. I.e. not even
experimental yet... but this is all a work in progress anyway.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Tue, 13 Sep 2022 20:32:20 +0100 |
parents | 8a8100fff580 |
children | 17b87fffdb91 |
rev | line source |
---|---|
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1 local base64 = require "util.encodings".base64; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
2 local sha1 = require "util.hashes".sha1; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
3 local st = require "util.stanza"; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
4 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
5 local sm_bind_resource = require "core.sessionmanager".bind_resource; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
6 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
7 local xmlns_bind2 = "urn:xmpp:bind2:1"; |
5039
c0d243b27e64
mod_sasl2, mod_sasl_bind2, mod_sasl2_sm: Bump XEP-0388 namespace
Matthew Wild <mwild1@gmail.com>
parents:
5037
diff
changeset
|
8 local xmlns_sasl2 = "urn:xmpp:sasl:2"; |
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
9 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
10 -- Advertise what we can do |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
11 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
12 module:hook("stream-features", function(event) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
13 local origin, features = event.origin, event.features; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
14 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
15 if origin.type ~= "c2s_unauthed" then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
16 return; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
17 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
18 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
19 local inline = st.stanza("inline", { xmlns = xmlns_bind2 }); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
20 module:fire_event("advertise-bind-features", { origin = origin, features = inline }); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
21 features:add_direct_child(inline); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
22 end, 1); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
23 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
24 module:hook("advertise-sasl-features", function(event) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
25 event.features:tag("bind", { xmlns = xmlns_bind2 }):up(); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
26 end, 1); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
27 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
28 -- Helper to actually bind a resource to a session |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
29 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
30 local function do_bind(session, bind_request) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
31 local resource; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
32 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
33 local client_id_tag = bind_request:get_child("client-id"); |
5032
71a84474fcfb
mod_sasl2_bind2: Use correct method to get text
Matthew Wild <mwild1@gmail.com>
parents:
5031
diff
changeset
|
34 local client_id = client_id_tag and client_id_tag:get_text() or session.client_id; |
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
35 if client_id and client_id ~= "" then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
36 local tag = client_id_tag and client_id_tag.attr.tag or "client"; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
37 resource = ("%s~%s"):format(tag, base64.encode(sha1(client_id):sub(1, 9))); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
38 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
39 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
40 local success, err_type, err, err_msg = sm_bind_resource(session, resource); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
41 if not success then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
42 session.log("debug", "Resource bind failed: %s", err_msg or err); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
43 return nil, { type = err_type, condition = err, text = err_msg }; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
44 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
45 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
46 session.log("debug", "Resource bound: %s", session.full_jid); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
47 return st.stanza("bound", { xmlns = xmlns_bind2 }) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
48 :text_tag("jid", session.full_jid) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
49 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
50 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
51 -- Enable inline features requested by the client |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
52 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
53 local function enable_features(session, bind_request, bind_result) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
54 local features = bind_request:get_child("features"); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
55 if not features then return; end |
5033
9afd98178011
mod_sasl2_bind2: Fix event name
Matthew Wild <mwild1@gmail.com>
parents:
5032
diff
changeset
|
56 module:fire_event("enable-bind-features", { |
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
57 session = session; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
58 features = features; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
59 result = bind_result; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
60 }); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
61 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
62 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
63 -- SASL 2 integration |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
64 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
65 module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
66 -- Cache action for future processing (after auth success) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
67 session.sasl2_bind_request = auth:child_with_ns(xmlns_bind2); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
68 end, 100); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
69 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
70 module:hook("sasl2/c2s/success", function (event) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
71 local session = event.session; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
72 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
73 local bind_request = session.sasl2_bind_request; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
74 if not bind_request then return; end -- No bind requested |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
75 session.sasl2_bind_request = nil; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
76 |
5037
8a8100fff580
mod_sasl2_bind2, mod_sasl2_sm: Move sasl2_sm_success to session
Matthew Wild <mwild1@gmail.com>
parents:
5036
diff
changeset
|
77 local sm_success = session.sasl2_sm_success; |
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
78 if sm_success and sm_success.type == "resumed" then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
79 return; -- No need to bind a resource |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
80 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
81 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
82 local bind_result, err = do_bind(session, bind_request); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
83 if not bind_result then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
84 bind_result = st.stanza("failed", { xmlns = xmlns_bind2 }) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
85 :add_error(err); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
86 else |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
87 enable_features(session, bind_request, bind_result); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
88 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
89 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
90 event.success:add_child(bind_result); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
91 end, 100); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
92 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
93 -- Inline features |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
94 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
95 module:hook("advertise-bind-features", function (event) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
96 local features = event.features; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
97 features:tag("feature", { var = "urn:xmpp:carbons:2" }):up(); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
98 features:tag("feature", { var = "urn:xmpp:csi:0" }):up(); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
99 end); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
100 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
101 module:hook("enable-bind-features", function (event) |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
102 local session, features = event.session, event.features; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
103 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
104 -- Carbons |
5036
9ef5625d0d39
mod_sasl2_bind2: Indicate to the client when carbons has been enabled
Matthew Wild <mwild1@gmail.com>
parents:
5033
diff
changeset
|
105 if features:get_child("enable", "urn:xmpp:carbons:2") then |
9ef5625d0d39
mod_sasl2_bind2: Indicate to the client when carbons has been enabled
Matthew Wild <mwild1@gmail.com>
parents:
5033
diff
changeset
|
106 session.want_carbons = true; |
9ef5625d0d39
mod_sasl2_bind2: Indicate to the client when carbons has been enabled
Matthew Wild <mwild1@gmail.com>
parents:
5033
diff
changeset
|
107 event.result:tag("enabled", { xmlns = "urn:xmpp:carbons:2" }):up(); |
9ef5625d0d39
mod_sasl2_bind2: Indicate to the client when carbons has been enabled
Matthew Wild <mwild1@gmail.com>
parents:
5033
diff
changeset
|
108 end |
5029
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
109 |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
110 -- CSI |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
111 local csi_state_tag = features:child_with_ns("urn:xmpp:csi:0"); |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
112 if csi_state_tag then |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
113 session.state = csi_state_tag.name; |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
114 end |
56b9f0b1409f
mod_sasl2_bind: Support for Bind 2.0 with SASL2
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
115 end, 10); |